Merge "Add rounded corners to QSDetail"
diff --git a/Android.bp b/Android.bp
index c97ee3d..9077344 100644
--- a/Android.bp
+++ b/Android.bp
@@ -352,12 +352,8 @@
"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 9974de4..3ba0dd2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4277,7 +4277,8 @@
method public void stopWatchingMode(android.app.AppOpsManager.OnOpChangedListener);
method public int unsafeCheckOp(String, int, String);
method public int unsafeCheckOpNoThrow(String, int, String);
- method public int unsafeCheckOpRaw(String, int, String);
+ method public int unsafeCheckOpRaw(@NonNull String, int, String);
+ method public int unsafeCheckOpRawNoThrow(@NonNull String, int, @NonNull String);
field public static final int MODE_ALLOWED = 0; // 0x0
field public static final int MODE_DEFAULT = 3; // 0x3
field public static final int MODE_ERRORED = 2; // 0x2
@@ -4446,7 +4447,7 @@
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();
@@ -10637,9 +10638,9 @@
}
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;
}
@@ -14155,6 +14156,7 @@
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);
@@ -16796,6 +16798,7 @@
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);
}
@@ -22856,7 +22859,6 @@
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();
@@ -22869,7 +22871,6 @@
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();
@@ -22885,7 +22886,6 @@
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);
@@ -23053,7 +23053,7 @@
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);
@@ -23392,11 +23392,11 @@
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 {
@@ -23497,7 +23497,7 @@
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;
}
@@ -23569,7 +23569,6 @@
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();
@@ -23689,18 +23688,18 @@
public abstract static class AudioTrack.StreamEventCallback {
ctor public AudioTrack.StreamEventCallback();
- method public void onDataRequest(@NonNull android.media.AudioTrack, int);
+ method public void onDataRequest(@NonNull android.media.AudioTrack, @IntRange(from=0) int);
method public void onPresentationEnded(@NonNull android.media.AudioTrack);
method public void onTearDown(@NonNull android.media.AudioTrack);
}
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);
}
@@ -23760,12 +23759,12 @@
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
@@ -23773,7 +23772,7 @@
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);
}
@@ -23982,13 +23981,13 @@
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);
@@ -25138,7 +25137,7 @@
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);
@@ -25326,7 +25325,6 @@
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();
@@ -25540,16 +25538,16 @@
}
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();
@@ -25559,11 +25557,11 @@
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();
@@ -25571,37 +25569,37 @@
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
@@ -25736,8 +25734,8 @@
}
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
@@ -26421,7 +26419,6 @@
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);
@@ -26617,15 +26614,15 @@
}
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>);
@@ -28980,6 +28977,7 @@
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
@@ -38419,7 +38417,8 @@
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);
@@ -41870,26 +41869,26 @@
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);
}
}
@@ -43355,14 +43354,14 @@
field @NonNull public static final android.os.Parcelable.Creator<android.telecom.CallIdentification> CREATOR;
}
- public static class CallIdentification.Builder {
+ public static final class CallIdentification.Builder {
ctor public CallIdentification.Builder();
- method public android.telecom.CallIdentification build();
- method public android.telecom.CallIdentification.Builder setDescription(@Nullable CharSequence);
- method public android.telecom.CallIdentification.Builder setDetails(@Nullable CharSequence);
- method public android.telecom.CallIdentification.Builder setName(@Nullable CharSequence);
- method public android.telecom.CallIdentification.Builder setNuisanceConfidence(int);
- method public android.telecom.CallIdentification.Builder setPhoto(@Nullable android.graphics.drawable.Icon);
+ method @NonNull public android.telecom.CallIdentification build();
+ method @NonNull public android.telecom.CallIdentification.Builder setDescription(@Nullable CharSequence);
+ method @NonNull public android.telecom.CallIdentification.Builder setDetails(@Nullable CharSequence);
+ method @NonNull public android.telecom.CallIdentification.Builder setName(@Nullable CharSequence);
+ method @NonNull public android.telecom.CallIdentification.Builder setNuisanceConfidence(int);
+ method @NonNull public android.telecom.CallIdentification.Builder setPhoto(@Nullable android.graphics.drawable.Icon);
}
public abstract class CallRedirectionService extends android.app.Service {
@@ -43983,8 +43982,8 @@
method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telecom.PhoneAccountHandle> getSelfManagedPhoneAccounts();
method public android.telecom.PhoneAccountHandle getSimCallManager();
- method public String getSystemDialerPackage();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telecom.PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
+ method @Nullable public String getSystemDialerPackage();
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public android.telecom.PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getVoiceMailNumber(android.telecom.PhoneAccountHandle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handleMmi(String, android.telecom.PhoneAccountHandle);
@@ -45145,8 +45144,8 @@
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();
@@ -45173,8 +45172,8 @@
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();
@@ -45470,6 +45469,7 @@
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
}
@@ -45559,7 +45559,7 @@
}
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();
@@ -47112,7 +47112,7 @@
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();
@@ -53036,7 +53036,7 @@
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);
@@ -53084,18 +53084,19 @@
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();
}
}
@@ -57331,7 +57332,7 @@
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 8b2109f..8dedd2c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -181,6 +181,7 @@
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";
@@ -362,27 +363,34 @@
field public static final String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
field public static final String OPSTR_WRITE_SMS = "android:write_sms";
field public static final String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
- field public static final int UID_STATE_BACKGROUND = 5; // 0x5
- field public static final int UID_STATE_CACHED = 6; // 0x6
- field public static final int UID_STATE_FOREGROUND = 4; // 0x4
- field public static final int UID_STATE_FOREGROUND_SERVICE = 3; // 0x3
- field public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 2; // 0x2
- field public static final int UID_STATE_PERSISTENT = 0; // 0x0
- field public static final int UID_STATE_TOP = 1; // 0x1
+ field public static final int OP_FLAGS_ALL = 31; // 0x1f
+ field public static final int OP_FLAGS_ALL_TRUSTED = 13; // 0xd
+ field public static final int OP_FLAG_SELF = 1; // 0x1
+ field public static final int OP_FLAG_TRUSTED_PROXIED = 8; // 0x8
+ field public static final int OP_FLAG_TRUSTED_PROXY = 2; // 0x2
+ field public static final int OP_FLAG_UNTRUSTED_PROXIED = 16; // 0x10
+ field public static final int OP_FLAG_UNTRUSTED_PROXY = 4; // 0x4
+ field public static final int UID_STATE_BACKGROUND = 600; // 0x258
+ field public static final int UID_STATE_CACHED = 700; // 0x2bc
+ field public static final int UID_STATE_FOREGROUND = 500; // 0x1f4
+ field public static final int UID_STATE_FOREGROUND_SERVICE = 400; // 0x190
+ field public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300; // 0x12c
+ field public static final int UID_STATE_PERSISTENT = 100; // 0x64
+ field public static final int UID_STATE_TOP = 200; // 0xc8
}
public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
method public int describeContents();
- method public long getAccessCount(int);
- method public long getAccessDuration(int);
- method public long getBackgroundAccessCount();
- method public long getBackgroundAccessDuration();
- method public long getBackgroundRejectCount();
- method public long getForegroundAccessCount();
- method public long getForegroundAccessDuration();
- method public long getForegroundRejectCount();
+ method public long getAccessCount(int, int, int);
+ method public long getAccessDuration(int, int, int);
+ method public long getBackgroundAccessCount(int);
+ method public long getBackgroundAccessDuration(int);
+ method public long getBackgroundRejectCount(int);
+ method public long getForegroundAccessCount(int);
+ method public long getForegroundAccessDuration(int);
+ method public long getForegroundRejectCount(int);
method @NonNull public String getOpName();
- method public long getRejectCount(int);
+ method public long getRejectCount(int, int, int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
}
@@ -404,6 +412,7 @@
public static final class AppOpsManager.HistoricalOpsRequest.Builder {
ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFlags(int);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setUid(int);
@@ -431,17 +440,24 @@
public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
method public int describeContents();
- method public int getDuration();
- method public long getLastAccessBackgroundTime();
- method public long getLastAccessForegroundTime();
- method public long getLastAccessTime();
- method public long getLastRejectBackgroundTime();
- method public long getLastRejectForegroundTime();
- method public long getLastRejectTime();
+ method public long getDuration();
+ method public long getLastAccessBackgroundTime(int);
+ method public long getLastAccessForegroundTime(int);
+ method public long getLastAccessTime(int);
+ method public long getLastAccessTime(int, int, int);
+ method public long getLastBackgroundDuration(int);
+ method public long getLastDuration(int, int, int);
+ method public long getLastForegroundDuration(int);
+ method public long getLastRejectBackgroundTime(int);
+ method public long getLastRejectForegroundTime(int);
+ method public long getLastRejectTime(int);
+ method public long getLastRejectTime(int, int, int);
method public int getMode();
- method public String getOpStr();
- method public String getProxyPackageName();
+ method @NonNull public String getOpStr();
+ method @Nullable public String getProxyPackageName();
+ method @Nullable public String getProxyPackageName(int, int);
method public int getProxyUid();
+ method public int getProxyUid(int, int);
method public boolean isRunning();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEntry> CREATOR;
@@ -450,7 +466,7 @@
public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
method public int describeContents();
method public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
- method public String getPackageName();
+ method @NonNull public String getPackageName();
method public int getUid();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
@@ -936,7 +952,7 @@
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;
@@ -944,8 +960,8 @@
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 {
@@ -983,7 +999,7 @@
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);
@@ -992,9 +1008,9 @@
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);
}
}
@@ -1172,7 +1188,7 @@
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);
@@ -3525,7 +3541,7 @@
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);
@@ -3538,7 +3554,7 @@
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();
@@ -3554,14 +3570,14 @@
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();
@@ -3663,7 +3679,7 @@
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;
@@ -3680,7 +3696,7 @@
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();
@@ -3692,7 +3708,7 @@
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;
@@ -5673,6 +5689,7 @@
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);
@@ -5692,7 +5709,7 @@
}
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();
@@ -5836,19 +5853,17 @@
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";
@@ -5867,10 +5882,6 @@
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);
}
@@ -5897,10 +5908,6 @@
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";
@@ -6418,8 +6425,8 @@
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);
}
}
@@ -6756,15 +6763,15 @@
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";
}
@@ -7070,8 +7077,8 @@
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsSupportingScheme(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
- method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.WRITE_SECURE_SETTINGS}) public boolean setDefaultDialer(String);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(android.telecom.PhoneAccountHandle);
+ method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.WRITE_SECURE_SETTINGS}) public boolean setDefaultDialer(@Nullable String);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
@@ -7091,12 +7098,12 @@
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;
}
@@ -7133,13 +7140,13 @@
}
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
@@ -7148,13 +7155,13 @@
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 {
@@ -7944,7 +7951,7 @@
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();
@@ -8420,7 +8427,7 @@
}
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);
@@ -8445,7 +8452,7 @@
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);
@@ -8749,12 +8756,12 @@
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();
@@ -8814,11 +8821,11 @@
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 {
@@ -8827,7 +8834,7 @@
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);
@@ -8848,7 +8855,7 @@
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);
@@ -9348,7 +9355,7 @@
method public static void logFileOperationFailure(int, int);
method public static void logFilePick(int, long, int, boolean, int, int, int);
method public static void logInvalidScopedAccessRequest(int);
- method public static void logPickerLaunchedFrom(String);
+ method public static void logPickerLaunchedFrom(@Nullable String);
method public static void logRootVisited(int, int);
method public static void logSearchMode(int);
method public static void logSearchType(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 4f7605b..684524e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -193,29 +193,36 @@
field public static final String OPSTR_WRITE_SMS = "android:write_sms";
field public static final String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
field public static final int OP_COARSE_LOCATION = 0; // 0x0
+ field public static final int OP_FLAGS_ALL = 31; // 0x1f
+ field public static final int OP_FLAG_SELF = 1; // 0x1
+ field public static final int OP_FLAG_TRUSTED_PROXIED = 8; // 0x8
+ field public static final int OP_FLAG_TRUSTED_PROXY = 2; // 0x2
+ field public static final int OP_FLAG_UNTRUSTED_PROXIED = 16; // 0x10
+ field public static final int OP_FLAG_UNTRUSTED_PROXY = 4; // 0x4
field public static final int OP_RECORD_AUDIO = 27; // 0x1b
+ field public static final int OP_START_FOREGROUND = 76; // 0x4c
field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18
- field public static final int UID_STATE_BACKGROUND = 5; // 0x5
- field public static final int UID_STATE_CACHED = 6; // 0x6
- field public static final int UID_STATE_FOREGROUND = 4; // 0x4
- field public static final int UID_STATE_FOREGROUND_SERVICE = 3; // 0x3
- field public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 2; // 0x2
- field public static final int UID_STATE_PERSISTENT = 0; // 0x0
- field public static final int UID_STATE_TOP = 1; // 0x1
+ field public static final int UID_STATE_BACKGROUND = 600; // 0x258
+ field public static final int UID_STATE_CACHED = 700; // 0x2bc
+ field public static final int UID_STATE_FOREGROUND = 500; // 0x1f4
+ field public static final int UID_STATE_FOREGROUND_SERVICE = 400; // 0x190
+ field public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300; // 0x12c
+ field public static final int UID_STATE_PERSISTENT = 100; // 0x64
+ field public static final int UID_STATE_TOP = 200; // 0xc8
}
public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
method public int describeContents();
- method public long getAccessCount(int);
- method public long getAccessDuration(int);
- method public long getBackgroundAccessCount();
- method public long getBackgroundAccessDuration();
- method public long getBackgroundRejectCount();
- method public long getForegroundAccessCount();
- method public long getForegroundAccessDuration();
- method public long getForegroundRejectCount();
+ method public long getAccessCount(int, int, int);
+ method public long getAccessDuration(int, int, int);
+ method public long getBackgroundAccessCount(int);
+ method public long getBackgroundAccessDuration(int);
+ method public long getBackgroundRejectCount(int);
+ method public long getForegroundAccessCount(int);
+ method public long getForegroundAccessDuration(int);
+ method public long getForegroundRejectCount(int);
method @NonNull public String getOpName();
- method public long getRejectCount(int);
+ method public long getRejectCount(int, int, int);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOp> CREATOR;
}
@@ -228,9 +235,9 @@
method public int getUidCount();
method @Nullable public android.app.AppOpsManager.HistoricalUidOps getUidOps(int);
method @NonNull public android.app.AppOpsManager.HistoricalUidOps getUidOpsAt(int);
- method public void increaseAccessCount(int, int, @NonNull String, int, long);
- method public void increaseAccessDuration(int, int, @NonNull String, int, long);
- method public void increaseRejectCount(int, int, @NonNull String, int, long);
+ method public void increaseAccessCount(int, int, @NonNull String, int, int, long);
+ method public void increaseAccessDuration(int, int, @NonNull String, int, int, long);
+ method public void increaseRejectCount(int, int, @NonNull String, int, int, long);
method public void offsetBeginAndEndTime(long);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalOps> CREATOR;
@@ -242,6 +249,7 @@
public static final class AppOpsManager.HistoricalOpsRequest.Builder {
ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFlags(int);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setUid(int);
@@ -271,6 +279,31 @@
method public void onOpActiveChanged(int, int, String, boolean);
}
+ public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getDuration();
+ method public long getLastAccessBackgroundTime(int);
+ method public long getLastAccessForegroundTime(int);
+ method public long getLastAccessTime(int);
+ method public long getLastAccessTime(int, int, int);
+ method public long getLastBackgroundDuration(int);
+ method public long getLastDuration(int, int, int);
+ method public long getLastForegroundDuration(int);
+ method public long getLastRejectBackgroundTime(int);
+ method public long getLastRejectForegroundTime(int);
+ method public long getLastRejectTime(int);
+ method public long getLastRejectTime(int, int, int);
+ method public int getMode();
+ method @NonNull public String getOpStr();
+ method @Nullable public String getProxyPackageName();
+ method @Nullable public String getProxyPackageName(int, int);
+ method public int getProxyUid();
+ method public int getProxyUid(int, int);
+ method public boolean isRunning();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEntry> CREATOR;
+ }
+
public class DownloadManager {
field public static final String COLUMN_MEDIASTORE_URI = "mediastore_uri";
}
@@ -978,7 +1011,7 @@
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;
@@ -3000,7 +3033,7 @@
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 012310c..77a56e5 100644
--- a/cmds/incident_helper/src/ih_util.cpp
+++ b/cmds/incident_helper/src/ih_util.cpp
@@ -142,7 +142,7 @@
}
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 21ced9c..5d525e6 100644
--- a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
@@ -65,8 +65,9 @@
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 ec4a839..aa3afc3 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 @@
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 da72002..7298da6 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -219,6 +219,7 @@
"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 a983b27..5968fa8 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -1568,7 +1568,7 @@
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 5c6d548..0e91f52 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -324,6 +324,12 @@
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 0ed2d75..7c2d242 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -162,6 +162,10 @@
}
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 0000000..c170b12
--- /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 46a956c..9b0e657 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2935,7 +2935,6 @@
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;->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;->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/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b654258..08239a1 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -332,7 +332,6 @@
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 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 @@
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 @@
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 @@
if (stopProfiling) {
mProfiler.stopProfiling();
}
- ensureJitEnabled();
return false;
}
}
@@ -2330,13 +2323,6 @@
}
}
- void ensureJitEnabled() {
- if (!mJitEnabled) {
- mJitEnabled = true;
- dalvik.system.VMRuntime.getRuntime().startJitCompilation();
- }
- }
-
@UnsupportedAppUsage
void scheduleGcIdler() {
if (!mGcIdlerScheduled) {
@@ -3782,7 +3768,6 @@
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
- ensureJitEnabled();
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -3896,7 +3881,6 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- ensureJitEnabled();
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
@@ -6177,9 +6161,6 @@
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 @@
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/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 5bf7ef5..91df05f 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -43,6 +43,8 @@
import android.os.UserManager;
import android.provider.Settings;
import android.util.ArrayMap;
+import android.util.LongSparseArray;
+import android.util.LongSparseLongArray;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
@@ -55,8 +57,10 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;
+import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
@@ -64,9 +68,11 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* API for interacting with "application operation" tracking.
@@ -227,7 +233,7 @@
/** @hide */
@Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = { "UID_STATE_" }, value = {
+ @IntDef(prefix = { "UID_STATE_" }, value = {
UID_STATE_PERSISTENT,
UID_STATE_TOP,
UID_STATE_FOREGROUND_SERVICE_LOCATION,
@@ -239,78 +245,322 @@
public @interface UidState {}
/**
- * Invalid UID state.
- * @hide
- */
- public static final int UID_STATE_INVALID = -1;
-
- /**
- * Metrics about an op when its uid is persistent.
+ * Uid state: The UID is a foreground persistent app.
* @hide
*/
@TestApi
@SystemApi
- public static final int UID_STATE_PERSISTENT = 0;
+ public static final int UID_STATE_PERSISTENT = 100;
/**
- * Metrics about an op when its uid is at the top.
+ * Uid state: The UID is top foreground app.
* @hide
*/
@TestApi
@SystemApi
- public static final int UID_STATE_TOP = 1;
+ public static final int UID_STATE_TOP = 200;
/**
- * Metrics about an op when its uid is running a foreground service with location type.
+ * Uid state: The UID is running a foreground service of location type.
* @hide
*/
@TestApi
@SystemApi
- public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 2;
+ public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300;
/**
- * Metrics about an op when its uid is running a foreground service.
+ * Uid state: The UID is running a foreground service.
* @hide
*/
@TestApi
@SystemApi
- public static final int UID_STATE_FOREGROUND_SERVICE = 3;
+ public static final int UID_STATE_FOREGROUND_SERVICE = 400;
/**
- * Last UID state in which we don't restrict what an op can do.
+ * The max, which is min priority, UID state for which any app op
+ * would be considered as performed in the foreground.
* @hide
*/
- public static final int UID_STATE_LAST_NON_RESTRICTED = UID_STATE_FOREGROUND_SERVICE_LOCATION;
+ public static final int UID_STATE_MAX_LAST_NON_RESTRICTED = UID_STATE_FOREGROUND_SERVICE;
/**
- * Metrics about an op when its uid is in the foreground for any other reasons.
+ * Uid state: The UID is a foreground app.
* @hide
*/
@TestApi
@SystemApi
- public static final int UID_STATE_FOREGROUND = 4;
+ public static final int UID_STATE_FOREGROUND = 500;
/**
- * Metrics about an op when its uid is in the background for any reason.
+ * Uid state: The UID is a background app.
* @hide
*/
@TestApi
@SystemApi
- public static final int UID_STATE_BACKGROUND = 5;
+ public static final int UID_STATE_BACKGROUND = 600;
/**
- * Metrics about an op when its uid is cached.
+ * Uid state: The UID is a cached app.
* @hide
*/
@TestApi
@SystemApi
- public static final int UID_STATE_CACHED = 6;
+ public static final int UID_STATE_CACHED = 700;
/**
- * Number of uid states we track.
+ * Uid state: The UID state with the highest priority.
* @hide
*/
- public static final int _NUM_UID_STATE = 7;
+ public static final int MAX_PRIORITY_UID_STATE = UID_STATE_PERSISTENT;
+
+ /**
+ * Uid state: The UID state with the lowest priority.
+ * @hide
+ */
+ public static final int MIN_PRIORITY_UID_STATE = UID_STATE_CACHED;
+
+ /**
+ * Resolves the first unrestricted state given an app op. Location is
+ * special as we want to allow its access only if a dedicated location
+ * foreground service is running. For other ops we consider any foreground
+ * service as a foreground state.
+ *
+ * @param op The op to resolve.
+ * @return The last restricted UID state.
+ *
+ * @hide
+ */
+ public static int resolveFirstUnrestrictedUidState(int op) {
+ switch (op) {
+ case OP_FINE_LOCATION:
+ case OP_COARSE_LOCATION: {
+ return UID_STATE_FOREGROUND_SERVICE_LOCATION;
+ }
+ }
+ return UID_STATE_FOREGROUND_SERVICE;
+ }
+
+ /**
+ * Resolves the last restricted state given an app op. Location is
+ * special as we want to allow its access only if a dedicated location
+ * foreground service is running. For other ops we consider any foreground
+ * service as a foreground state.
+ *
+ * @param op The op to resolve.
+ * @return The last restricted UID state.
+ *
+ * @hide
+ */
+ public static int resolveLastRestrictedUidState(int op) {
+ switch (op) {
+ case OP_FINE_LOCATION:
+ case OP_COARSE_LOCATION: {
+ return UID_STATE_FOREGROUND_SERVICE;
+ }
+ }
+ return UID_STATE_FOREGROUND;
+ }
+
+ /** @hide Note: Keep these sorted */
+ public static final int[] UID_STATES = {
+ UID_STATE_PERSISTENT,
+ UID_STATE_TOP,
+ UID_STATE_FOREGROUND_SERVICE_LOCATION,
+ UID_STATE_FOREGROUND_SERVICE,
+ UID_STATE_FOREGROUND,
+ UID_STATE_BACKGROUND,
+ UID_STATE_CACHED
+ };
+
+ /** @hide */
+ public static String getUidStateName(@UidState int uidState) {
+ switch (uidState) {
+ case UID_STATE_PERSISTENT:
+ return "pers";
+ case UID_STATE_TOP:
+ return "top";
+ case UID_STATE_FOREGROUND_SERVICE_LOCATION:
+ return "fgsvcl";
+ case UID_STATE_FOREGROUND_SERVICE:
+ return "fgsvc";
+ case UID_STATE_FOREGROUND:
+ return "fg";
+ case UID_STATE_BACKGROUND:
+ return "bg";
+ case UID_STATE_CACHED:
+ return "cch";
+ default:
+ return "unknown";
+ }
+ }
+
+ /**
+ * Flag: non proxy operations. These are operations
+ * performed on behalf of the app itself and not on behalf of
+ * another one.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final int OP_FLAG_SELF = 0x1;
+
+ /**
+ * Flag: trusted proxy operations. These are operations
+ * performed on behalf of another app by a trusted app.
+ * Which is work a trusted app blames on another app.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final int OP_FLAG_TRUSTED_PROXY = 0x2;
+
+ /**
+ * Flag: untrusted proxy operations. These are operations
+ * performed on behalf of another app by an untrusted app.
+ * Which is work an untrusted app blames on another app.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final int OP_FLAG_UNTRUSTED_PROXY = 0x4;
+
+ /**
+ * Flag: trusted proxied operations. These are operations
+ * performed by a trusted other app on behalf of an app.
+ * Which is work an app was blamed for by a trusted app.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final int OP_FLAG_TRUSTED_PROXIED = 0x8;
+
+ /**
+ * Flag: untrusted proxied operations. These are operations
+ * performed by an untrusted other app on behalf of an app.
+ * Which is work an app was blamed for by an untrusted app.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final int OP_FLAG_UNTRUSTED_PROXIED = 0x10;
+
+ /**
+ * Flags: all operations. These include operations matched
+ * by {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ public static final int OP_FLAGS_ALL =
+ OP_FLAG_SELF
+ | OP_FLAG_TRUSTED_PROXY
+ | OP_FLAG_UNTRUSTED_PROXY
+ | OP_FLAG_TRUSTED_PROXIED
+ | OP_FLAG_UNTRUSTED_PROXIED;
+
+ /**
+ * Flags: all trusted operations which is ones either the app did {@link #OP_FLAG_SELF},
+ * or it was blamed for by a trusted app {@link #OP_FLAG_TRUSTED_PROXIED}, or ones the
+ * app if untrusted blamed on other apps {@link #OP_FLAG_UNTRUSTED_PROXY}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int OP_FLAGS_ALL_TRUSTED = AppOpsManager.OP_FLAG_SELF
+ | AppOpsManager.OP_FLAG_UNTRUSTED_PROXY
+ | AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "FLAG_" }, value = {
+ OP_FLAG_SELF,
+ OP_FLAG_TRUSTED_PROXY,
+ OP_FLAG_UNTRUSTED_PROXY,
+ OP_FLAG_TRUSTED_PROXIED,
+ OP_FLAG_UNTRUSTED_PROXIED
+ })
+ public @interface OpFlags {}
+
+
+ /** @hide */
+ public static final String getFlagName(@OpFlags int flag) {
+ switch (flag) {
+ case OP_FLAG_SELF:
+ return "s";
+ case OP_FLAG_TRUSTED_PROXY:
+ return "tp";
+ case OP_FLAG_UNTRUSTED_PROXY:
+ return "up";
+ case OP_FLAG_TRUSTED_PROXIED:
+ return "tpd";
+ case OP_FLAG_UNTRUSTED_PROXIED:
+ return "upd";
+ default:
+ return "unknown";
+ }
+ }
+
+ private static final int UID_STATE_OFFSET = 31;
+ private static final int FLAGS_MASK = 0xFFFFFFFF;
+
+ /**
+ * Key for a data bucket storing app op state. The bucket
+ * is composed of the uid state and state flags. This way
+ * we can query data for given uid state and a set of flags where
+ * the flags control which type of data to get. For example,
+ * one can get the ops an app did on behalf of other apps
+ * while in the background.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @Target({ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD})
+ public @interface DataBucketKey {
+ }
+
+ /** @hide */
+ public static String keyToString(@DataBucketKey long key) {
+ final int uidState = extractUidStateFromKey(key);
+ final int flags = extractFlagsFromKey(key);
+ return "[" + getUidStateName(uidState) + "-" + flagsToString(flags) + "]";
+ }
+
+ /** @hide */
+ public static @DataBucketKey long makeKey(@UidState int uidState, @OpFlags int flags) {
+ return ((long) uidState << UID_STATE_OFFSET) | flags;
+ }
+
+ /** @hide */
+ public static int extractUidStateFromKey(@DataBucketKey long key) {
+ return (int) (key >> UID_STATE_OFFSET);
+ }
+
+ /** @hide */
+ public static int extractFlagsFromKey(@DataBucketKey long key) {
+ return (int) (key & FLAGS_MASK);
+ }
+
+ /** @hide */
+ public static String flagsToString(@OpFlags int flags) {
+ final StringBuilder flagsBuilder = new StringBuilder();
+ while (flags != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(flags);
+ flags &= ~flag;
+ if (flagsBuilder.length() > 0) {
+ flagsBuilder.append('|');
+ }
+ flagsBuilder.append(getFlagName(flag));
+ }
+ return flagsBuilder.toString();
+ }
// when adding one of these:
// - increment _NUM_OP
@@ -551,7 +801,7 @@
@UnsupportedAppUsage
public static final int OP_MANAGE_IPSEC_TUNNELS = 75;
/** @hide Any app start foreground service. */
- @UnsupportedAppUsage
+ @TestApi
public static final int OP_START_FOREGROUND = 76;
/** @hide */
@UnsupportedAppUsage
@@ -1947,14 +2197,23 @@
mEntries = entries;
}
- public String getPackageName() {
+ /**
+ * @return The name of the package.
+ */
+ public @NonNull String getPackageName() {
return mPackageName;
}
+ /**
+ * @return The uid of the package.
+ */
public int getUid() {
return mUid;
}
+ /**
+ * @return The ops of the package.
+ */
public List<OpEntry> getOps() {
return mEntries;
}
@@ -1999,57 +2258,59 @@
* Class holding the information about one unique operation of an application.
* @hide
*/
+ @TestApi
+ @Immutable
@SystemApi
public static final class OpEntry implements Parcelable {
private final int mOp;
- private final @Mode int mMode;
- private final long[] mTimes;
- private final long[] mRejectTimes;
- private final int mDuration;
- private final int mProxyUid;
private final boolean mRunning;
- private final String mProxyPackageName;
+ private final @Mode int mMode;
+ private final @Nullable LongSparseLongArray mAccessTimes;
+ private final @Nullable LongSparseLongArray mRejectTimes;
+ private final @Nullable LongSparseLongArray mDurations;
+ private final @Nullable LongSparseLongArray mProxyUids;
+ private final @Nullable LongSparseArray<String> mProxyPackageNames;
/**
* @hide
*/
- public OpEntry(int op, @Mode int mode, long time, long rejectTime, int duration,
- int proxyUid, String proxyPackage) {
+ public OpEntry(int op, boolean running, @Mode int mode,
+ @Nullable LongSparseLongArray accessTimes, @Nullable LongSparseLongArray rejectTimes,
+ @Nullable LongSparseLongArray durations, @Nullable LongSparseLongArray proxyUids,
+ @Nullable LongSparseArray<String> proxyPackageNames) {
mOp = op;
- mMode = mode;
- mTimes = new long[_NUM_UID_STATE];
- mRejectTimes = new long[_NUM_UID_STATE];
- mTimes[0] = time;
- mRejectTimes[0] = rejectTime;
- mDuration = duration;
- mRunning = duration == -1;
- mProxyUid = proxyUid;
- mProxyPackageName = proxyPackage;
- }
-
- /**
- * @hide
- */
- public OpEntry(int op, @Mode int mode, long[] times, long[] rejectTimes, int duration,
- boolean running, int proxyUid, String proxyPackage) {
- mOp = op;
- mMode = mode;
- mTimes = new long[_NUM_UID_STATE];
- mRejectTimes = new long[_NUM_UID_STATE];
- System.arraycopy(times, 0, mTimes, 0, _NUM_UID_STATE);
- System.arraycopy(rejectTimes, 0, mRejectTimes, 0, _NUM_UID_STATE);
- mDuration = duration;
mRunning = running;
- mProxyUid = proxyUid;
- mProxyPackageName = proxyPackage;
+ mMode = mode;
+ mAccessTimes = accessTimes;
+ mRejectTimes = rejectTimes;
+ mDurations = durations;
+ mProxyUids = proxyUids;
+ mProxyPackageNames = proxyPackageNames;
}
/**
* @hide
*/
- public OpEntry(int op, @Mode int mode, long[] times, long[] rejectTimes, int duration,
- int proxyUid, String proxyPackage) {
- this(op, mode, times, rejectTimes, duration, duration == -1, proxyUid, proxyPackage);
+ public OpEntry(int op, @Mode int mode) {
+ mOp = op;
+ mMode = mode;
+ mRunning = false;
+ mAccessTimes = null;
+ mRejectTimes = null;
+ mDurations = null;
+ mProxyUids = null;
+ mProxyPackageNames = null;
+ }
+
+ /**
+ * Returns all keys for which we have mapped state in any of the data buckets -
+ * access time, reject time, duration.
+ * @hide */
+ public @Nullable LongSparseArray<Object> collectKeys() {
+ LongSparseArray<Object> result = AppOpsManager.collectKeys(mAccessTimes, null);
+ result = AppOpsManager.collectKeys(mRejectTimes, result);
+ result = AppOpsManager.collectKeys(mDurations, result);
+ return result;
}
/**
@@ -2061,14 +2322,14 @@
}
/**
- * Return this entry's op string name, such as {@link #OPSTR_COARSE_LOCATION}.
+ * @return This entry's op string name, such as {@link #OPSTR_COARSE_LOCATION}.
*/
- public String getOpStr() {
+ public @NonNull String getOpStr() {
return sOpToString[mOp];
}
/**
- * Return this entry's current mode, such as {@link #MODE_ALLOWED}.
+ * @return this entry's current mode, such as {@link #MODE_ALLOWED}.
*/
public @Mode int getMode() {
return mMode;
@@ -2079,89 +2340,331 @@
*/
@UnsupportedAppUsage
public long getTime() {
- return maxTime(mTimes, 0, _NUM_UID_STATE);
+ return getLastAccessTime(OP_FLAGS_ALL);
}
/**
- * Return the last wall clock time this op was accessed by the app.
+ * Return the last wall clock time in milliseconds this op was accessed.
+ *
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the last access time in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ *
+ * @see #getLastAccessForegroundTime(int)
+ * @see #getLastAccessBackgroundTime(int)
+ * @see #getLastAccessTime(int, int, int)
*/
- public long getLastAccessTime() {
- return maxTime(mTimes, 0, _NUM_UID_STATE);
+ public long getLastAccessTime(@OpFlags int flags) {
+ return maxForFlagsInStates(mAccessTimes, MAX_PRIORITY_UID_STATE,
+ MIN_PRIORITY_UID_STATE, flags);
}
/**
- * Return the last wall clock time this op was accessed by the app while in the foreground.
+ * Return the last wall clock time in milliseconds this op was accessed
+ * by the app while in the foreground.
+ *
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the last foreground access time in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ *
+ * @see #getLastAccessBackgroundTime(int)
+ * @see #getLastAccessTime(int)
+ * @see #getLastAccessTime(int, int, int)
*/
- public long getLastAccessForegroundTime() {
- return maxTime(mTimes, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
+ public long getLastAccessForegroundTime(@OpFlags int flags) {
+ return maxForFlagsInStates(mAccessTimes, MAX_PRIORITY_UID_STATE,
+ resolveFirstUnrestrictedUidState(mOp), flags);
}
/**
- * Return the last wall clock time this op was accessed by the app while in the background.
+ * Return the last wall clock time in milliseconds this op was accessed
+ * by the app while in the background.
+ *
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the last foreground access time in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ *
+ * @see #getLastAccessForegroundTime(int)
+ * @see #getLastAccessTime(int)
+ * @see #getLastAccessTime(int, int, int)
*/
- public long getLastAccessBackgroundTime() {
- return maxTime(mTimes, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
+ public long getLastAccessBackgroundTime(@OpFlags int flags) {
+ return maxForFlagsInStates(mAccessTimes, resolveLastRestrictedUidState(mOp),
+ MIN_PRIORITY_UID_STATE, flags);
}
/**
- * @hide
+ * Return the last wall clock time in milliseconds this op was accessed
+ * by the app for a given range of UID states.
+ *
+ * @param fromUidState The UID state for which to query. Could be one of
+ * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
+ * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
+ * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
+ * @param toUidState The UID state for which to query.
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ *
+ * @return the last foreground access time in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ *
+ * @see #getLastAccessForegroundTime(int)
+ * @see #getLastAccessBackgroundTime(int)
+ * @see #getLastAccessTime(int)
*/
- public long getLastTimeFor(int uidState) {
- return mTimes[uidState];
+ public long getLastAccessTime(@UidState int fromUidState, @UidState int toUidState,
+ @OpFlags int flags) {
+ return maxForFlagsInStates(mAccessTimes, fromUidState, toUidState, flags);
}
/**
* @hide
*/
public long getRejectTime() {
- return maxTime(mRejectTimes, 0, _NUM_UID_STATE);
+ return getLastRejectTime(OP_FLAGS_ALL);
}
/**
- * Return the last wall clock time the app made an attempt to access this op but
- * was rejected.
+ * Return the last wall clock time in milliseconds the app made an attempt
+ * to access this op but was rejected.
+ *
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the last reject time in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ *
+ * @see #getLastRejectBackgroundTime(int)
+ * @see #getLastRejectForegroundTime(int)
+ * @see #getLastRejectTime(int, int, int)
*/
- public long getLastRejectTime() {
- return maxTime(mRejectTimes, 0, _NUM_UID_STATE);
+ public long getLastRejectTime(@OpFlags int flags) {
+ return maxForFlagsInStates(mRejectTimes, MAX_PRIORITY_UID_STATE,
+ MIN_PRIORITY_UID_STATE, flags);
}
/**
- * Return the last wall clock time the app made an attempt to access this op while in
- * the foreground but was rejected.
+ * Return the last wall clock time in milliseconds the app made an attempt
+ * to access this op while in the foreground but was rejected.
+ *
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the last foreground reject time in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ *
+ * @see #getLastRejectBackgroundTime(int)
+ * @see #getLastRejectTime(int, int, int)
+ * @see #getLastRejectTime(int)
*/
- public long getLastRejectForegroundTime() {
- return maxTime(mRejectTimes, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
+ public long getLastRejectForegroundTime(@OpFlags int flags) {
+ return maxForFlagsInStates(mRejectTimes, MAX_PRIORITY_UID_STATE,
+ resolveFirstUnrestrictedUidState(mOp), flags);
}
/**
- * Return the last wall clock time the app made an attempt to access this op while in
- * the background but was rejected.
+ * Return the last wall clock time in milliseconds the app made an attempt
+ * to access this op while in the background but was rejected.
+ *
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the last background reject time in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ *
+ * @see #getLastRejectForegroundTime(int)
+ * @see #getLastRejectTime(int, int, int)
+ * @see #getLastRejectTime(int)
*/
- public long getLastRejectBackgroundTime() {
- return maxTime(mRejectTimes, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
+ public long getLastRejectBackgroundTime(@OpFlags int flags) {
+ return maxForFlagsInStates(mRejectTimes, resolveLastRestrictedUidState(mOp),
+ MIN_PRIORITY_UID_STATE, flags);
}
/**
- * @hide
+ * Return the last wall clock time state in milliseconds the app made an
+ * attempt to access this op for a given range of UID states.
+ *
+ * @param fromUidState The UID state from which to query. Could be one of
+ * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
+ * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
+ * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
+ * @param toUidState The UID state to which to query.
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the last foreground access time in milliseconds since
+ * epoch start (January 1, 1970 00:00:00.000 GMT - Gregorian).
+ *
+ * @see #getLastRejectForegroundTime(int)
+ * @see #getLastRejectBackgroundTime(int)
+ * @see #getLastRejectTime(int)
*/
- public long getLastRejectTimeFor(int uidState) {
- return mRejectTimes[uidState];
+ public long getLastRejectTime(@UidState int fromUidState, @UidState int toUidState,
+ @OpFlags int flags) {
+ return maxForFlagsInStates(mRejectTimes, fromUidState, toUidState, flags);
}
+ /**
+ * @return Whether the operation is running.
+ */
public boolean isRunning() {
return mRunning;
}
- public int getDuration() {
- return mDuration;
+ /**
+ * @return The duration of the operation in milliseconds.
+ */
+ public long getDuration() {
+ return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
}
+ /**
+ * Return the duration in milliseconds the app accessed this op while
+ * in the foreground.
+ *
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the foreground access duration in milliseconds.
+ *
+ * @see #getLastBackgroundDuration(int)
+ * @see #getLastDuration(int, int, int)
+ */
+ public long getLastForegroundDuration(@OpFlags int flags) {
+ return sumForFlagsInStates(mDurations, MAX_PRIORITY_UID_STATE,
+ resolveFirstUnrestrictedUidState(mOp), flags);
+ }
+
+ /**
+ * Return the duration in milliseconds the app accessed this op while
+ * in the background.
+ *
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the background access duration in milliseconds.
+ *
+ * @see #getLastForegroundDuration(int)
+ * @see #getLastDuration(int, int, int)
+ */
+ public long getLastBackgroundDuration(@OpFlags int flags) {
+ return sumForFlagsInStates(mDurations, resolveLastRestrictedUidState(mOp),
+ MIN_PRIORITY_UID_STATE, flags);
+ }
+
+ /**
+ * Return the duration in milliseconds the app accessed this op for
+ * a given range of UID states.
+ *
+ * @param fromUidState The UID state for which to query. Could be one of
+ * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
+ * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
+ * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
+ * @param toUidState The UID state for which to query.
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return the access duration in milliseconds.
+ */
+ public long getLastDuration(@UidState int fromUidState, @UidState int toUidState,
+ @OpFlags int flags) {
+ return sumForFlagsInStates(mDurations, fromUidState, toUidState, flags);
+ }
+
+ /**
+ * Gets the UID of the app that performed the op on behalf of this app and
+ * as a result blamed the op on this app or {@link Process#INVALID_UID} if
+ * there is no proxy.
+ *
+ * @return The proxy UID.
+ */
public int getProxyUid() {
- return mProxyUid;
+ return (int) findFirstNonNegativeForFlagsInStates(mDurations,
+ MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
}
- public String getProxyPackageName() {
- return mProxyPackageName;
+ /**
+ * Gets the UID of the app that performed the op on behalf of this app and
+ * as a result blamed the op on this app or {@link Process#INVALID_UID} if
+ * there is no proxy.
+ *
+ * @param uidState The UID state for which to query. Could be one of
+ * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
+ * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
+ * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ *
+ * @return The proxy UID.
+ */
+ public int getProxyUid(@UidState int uidState, @OpFlags int flags) {
+ return (int) findFirstNonNegativeForFlagsInStates(mDurations,
+ uidState, uidState, flags);
+ }
+
+ /**
+ * Gets the package name of the app that performed the op on behalf of this
+ * app and as a result blamed the op on this app or {@code null}
+ * if there is no proxy.
+ *
+ * @return The proxy package name.
+ */
+ public @Nullable String getProxyPackageName() {
+ return findFirstNonNullForFlagsInStates(mProxyPackageNames, MAX_PRIORITY_UID_STATE,
+ MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);
+ }
+
+ /**
+ * Gets the package name of the app that performed the op on behalf of this
+ * app and as a result blamed the op on this app for a UID state or
+ * {@code null} if there is no proxy.
+ *
+ * @param uidState The UID state for which to query. Could be one of
+ * {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
+ * {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
+ * {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return The proxy package name.
+ */
+ public @Nullable String getProxyPackageName(@UidState int uidState, @OpFlags int flags) {
+ return findFirstNonNullForFlagsInStates(mProxyPackageNames, uidState, uidState, flags);
}
@Override
@@ -2173,23 +2676,23 @@
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mOp);
dest.writeInt(mMode);
- dest.writeLongArray(mTimes);
- dest.writeLongArray(mRejectTimes);
- dest.writeInt(mDuration);
dest.writeBoolean(mRunning);
- dest.writeInt(mProxyUid);
- dest.writeString(mProxyPackageName);
+ writeLongSparseLongArrayToParcel(mAccessTimes, dest);
+ writeLongSparseLongArrayToParcel(mRejectTimes, dest);
+ writeLongSparseLongArrayToParcel(mDurations, dest);
+ writeLongSparseLongArrayToParcel(mProxyUids, dest);
+ writeLongSparseStringArrayToParcel(mProxyPackageNames, dest);
}
OpEntry(Parcel source) {
mOp = source.readInt();
mMode = source.readInt();
- mTimes = source.createLongArray();
- mRejectTimes = source.createLongArray();
- mDuration = source.readInt();
mRunning = source.readBoolean();
- mProxyUid = source.readInt();
- mProxyPackageName = source.readString();
+ mAccessTimes = readLongSparseLongArrayFromParcel(source);
+ mRejectTimes = readLongSparseLongArrayFromParcel(source);
+ mDurations = readLongSparseLongArrayFromParcel(source);
+ mProxyUids = readLongSparseLongArrayFromParcel(source);
+ mProxyPackageNames = readLongSparseStringArrayFromParcel(source);
}
public static final @android.annotation.NonNull Creator<OpEntry> CREATOR = new Creator<OpEntry>() {
@@ -2226,14 +2729,17 @@
private final @Nullable List<String> mOpNames;
private final long mBeginTimeMillis;
private final long mEndTimeMillis;
+ private final @OpFlags int mFlags;
private HistoricalOpsRequest(int uid, @Nullable String packageName,
- @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis) {
+ @Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
+ @OpFlags int flags) {
mUid = uid;
mPackageName = packageName;
mOpNames = opNames;
mBeginTimeMillis = beginTimeMillis;
mEndTimeMillis = endTimeMillis;
+ mFlags = flags;
}
/**
@@ -2249,6 +2755,7 @@
private @Nullable List<String> mOpNames;
private final long mBeginTimeMillis;
private final long mEndTimeMillis;
+ private @OpFlags int mFlags = OP_FLAGS_ALL;
/**
* Creates a new builder.
@@ -2311,11 +2818,28 @@
}
/**
+ * Sets the op flags to query for. The flags specify the type of
+ * op data being queried.
+ *
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
+ * @return This builder.
+ */
+ public @NonNull Builder setFlags(@OpFlags int flags) {
+ Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL);
+ mFlags = flags;
+ return this;
+ }
+
+ /**
* @return a new {@link HistoricalOpsRequest}.
*/
public @NonNull HistoricalOpsRequest build() {
return new HistoricalOpsRequest(mUid, mPackageName, mOpNames,
- mBeginTimeMillis, mEndTimeMillis);
+ mBeginTimeMillis, mEndTimeMillis, mFlags);
}
}
}
@@ -2521,25 +3045,25 @@
/** @hide */
@TestApi
public void increaseAccessCount(int opCode, int uid, @NonNull String packageName,
- @UidState int uidState, long increment) {
+ @UidState int uidState, @OpFlags int flags, long increment) {
getOrCreateHistoricalUidOps(uid).increaseAccessCount(opCode,
- packageName, uidState, increment);
+ packageName, uidState, flags, increment);
}
/** @hide */
@TestApi
public void increaseRejectCount(int opCode, int uid, @NonNull String packageName,
- @UidState int uidState, long increment) {
+ @UidState int uidState, @OpFlags int flags, long increment) {
getOrCreateHistoricalUidOps(uid).increaseRejectCount(opCode,
- packageName, uidState, increment);
+ packageName, uidState, flags, increment);
}
/** @hide */
@TestApi
public void increaseAccessDuration(int opCode, int uid, @NonNull String packageName,
- @UidState int uidState, long increment) {
+ @UidState int uidState, @OpFlags int flags, long increment) {
getOrCreateHistoricalUidOps(uid).increaseAccessDuration(opCode,
- packageName, uidState, increment);
+ packageName, uidState, flags, increment);
}
/** @hide */
@@ -2834,21 +3358,21 @@
}
private void increaseAccessCount(int opCode, @NonNull String packageName,
- @UidState int uidState, long increment) {
+ @UidState int uidState, @OpFlags int flags, long increment) {
getOrCreateHistoricalPackageOps(packageName).increaseAccessCount(
- opCode, uidState, increment);
+ opCode, uidState, flags, increment);
}
private void increaseRejectCount(int opCode, @NonNull String packageName,
- @UidState int uidState, long increment) {
+ @UidState int uidState, @OpFlags int flags, long increment) {
getOrCreateHistoricalPackageOps(packageName).increaseRejectCount(
- opCode, uidState, increment);
+ opCode, uidState, flags, increment);
}
private void increaseAccessDuration(int opCode, @NonNull String packageName,
- @UidState int uidState, long increment) {
+ @UidState int uidState, @OpFlags int flags, long increment) {
getOrCreateHistoricalPackageOps(packageName).increaseAccessDuration(
- opCode, uidState, increment);
+ opCode, uidState, flags, increment);
}
/**
@@ -3070,16 +3594,19 @@
return true;
}
- private void increaseAccessCount(int opCode, @UidState int uidState, long increment) {
- getOrCreateHistoricalOp(opCode).increaseAccessCount(uidState, increment);
+ private void increaseAccessCount(int opCode, @UidState int uidState,
+ @OpFlags int flags, long increment) {
+ getOrCreateHistoricalOp(opCode).increaseAccessCount(uidState, flags, increment);
}
- private void increaseRejectCount(int opCode, @UidState int uidState, long increment) {
- getOrCreateHistoricalOp(opCode).increaseRejectCount(uidState, increment);
+ private void increaseRejectCount(int opCode, @UidState int uidState,
+ @OpFlags int flags, long increment) {
+ getOrCreateHistoricalOp(opCode).increaseRejectCount(uidState, flags, increment);
}
- private void increaseAccessDuration(int opCode, @UidState int uidState, long increment) {
- getOrCreateHistoricalOp(opCode).increaseAccessDuration(uidState, increment);
+ private void increaseAccessDuration(int opCode, @UidState int uidState,
+ @OpFlags int flags, long increment) {
+ getOrCreateHistoricalOp(opCode).increaseAccessDuration(uidState, flags, increment);
}
/**
@@ -3095,7 +3622,6 @@
* Gets number historical app ops.
*
* @return The number historical app ops.
- *
* @see #getOpAt(int)
*/
public int getOpCount() {
@@ -3109,9 +3635,7 @@
* Gets the historical op at a given index.
*
* @param index The index to lookup.
- *
* @return The op at the given index.
- *
* @see #getOpCount()
*/
public @NonNull HistoricalOp getOpAt(int index) {
@@ -3125,7 +3649,6 @@
* Gets the historical entry for a given op name.
*
* @param opName The op name.
- *
* @return The historical entry for that op name.
*/
public @Nullable HistoricalOp getOp(@NonNull String opName) {
@@ -3219,39 +3742,33 @@
@SystemApi
public static final class HistoricalOp implements Parcelable {
private final int mOp;
- private @Nullable long[] mAccessCount;
- private @Nullable long[] mRejectCount;
- private @Nullable long[] mAccessDuration;
+ private @Nullable LongSparseLongArray mAccessCount;
+ private @Nullable LongSparseLongArray mRejectCount;
+ private @Nullable LongSparseLongArray mAccessDuration;
/** @hide */
public HistoricalOp(int op) {
mOp = op;
- mAccessCount = new long[_NUM_UID_STATE];
- mRejectCount = new long[_NUM_UID_STATE];
- mAccessDuration = new long[_NUM_UID_STATE];
}
private HistoricalOp(@NonNull HistoricalOp other) {
mOp = other.mOp;
if (other.mAccessCount != null) {
- System.arraycopy(other.mAccessCount, 0, getOrCreateAccessCount(),
- 0, other.mAccessCount.length);
+ mAccessCount = other.mAccessCount.clone();
}
if (other.mRejectCount != null) {
- System.arraycopy(other.mRejectCount, 0, getOrCreateRejectCount(),
- 0, other.mRejectCount.length);
+ mRejectCount = other.mRejectCount.clone();
}
if (other.mAccessDuration != null) {
- System.arraycopy(other.mAccessDuration, 0, getOrCreateAccessDuration(),
- 0, other.mAccessDuration.length);
+ mAccessDuration = other.mAccessDuration.clone();
}
}
private HistoricalOp(@NonNull Parcel parcel) {
mOp = parcel.readInt();
- mAccessCount = parcel.createLongArray();
- mRejectCount = parcel.createLongArray();
- mAccessDuration = parcel.createLongArray();
+ mAccessCount = readLongSparseLongArrayFromParcel(parcel);
+ mRejectCount = readLongSparseLongArrayFromParcel(parcel);
+ mAccessDuration = readLongSparseLongArrayFromParcel(parcel);
}
private void filter(double scaleFactor) {
@@ -3266,90 +3783,64 @@
&& !hasData(mAccessDuration);
}
- private boolean hasData(@NonNull long[] array) {
- for (long value : array) {
- if (value != 0) {
- return true;
- }
- }
- return false;
+ private boolean hasData(@NonNull LongSparseLongArray array) {
+ return (array != null && array.size() > 0);
}
private @Nullable HistoricalOp splice(double fractionToRemove) {
- HistoricalOp splice = null;
- if (mAccessCount != null) {
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- final long spliceAccessCount = Math.round(
- mAccessCount[i] * fractionToRemove);
- if (spliceAccessCount > 0) {
- if (splice == null) {
- splice = new HistoricalOp(mOp);
- }
- splice.getOrCreateAccessCount()[i] = spliceAccessCount;
- mAccessCount[i] -= spliceAccessCount;
- }
- }
- }
-
- if (mRejectCount != null) {
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- final long spliceRejectCount = Math.round(
- mRejectCount[i] * fractionToRemove);
-
- if (spliceRejectCount > 0) {
- if (splice == null) {
- splice = new HistoricalOp(mOp);
- }
- splice.getOrCreateRejectCount()[i] = spliceRejectCount;
- mRejectCount[i] -= spliceRejectCount;
- }
- }
- }
-
- if (mAccessDuration != null) {
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- final long spliceAccessDuration = Math.round(
- mAccessDuration[i] * fractionToRemove);
- if (spliceAccessDuration > 0) {
- if (splice == null) {
- splice = new HistoricalOp(mOp);
- }
- splice.getOrCreateAccessDuration()[i] = spliceAccessDuration;
- mAccessDuration[i] -= spliceAccessDuration;
- }
- }
- }
+ final HistoricalOp splice = new HistoricalOp(mOp);
+ splice(mAccessCount, splice::getOrCreateAccessCount, fractionToRemove);
+ splice(mRejectCount, splice::getOrCreateRejectCount, fractionToRemove);
+ splice(mAccessDuration, splice::getOrCreateAccessDuration, fractionToRemove);
return splice;
}
+ private static void splice(@Nullable LongSparseLongArray sourceContainer,
+ @NonNull Supplier<LongSparseLongArray> destContainerProvider,
+ double fractionToRemove) {
+ if (sourceContainer != null) {
+ final int size = sourceContainer.size();
+ for (int i = 0; i < size; i++) {
+ final long key = sourceContainer.keyAt(i);
+ final long value = sourceContainer.valueAt(i);
+ final long removedFraction = Math.round(value * fractionToRemove);
+ if (removedFraction > 0) {
+ destContainerProvider.get().put(key, removedFraction);
+ sourceContainer.put(key, value - removedFraction);
+ }
+ }
+ }
+ }
+
private void merge(@NonNull HistoricalOp other) {
- if (other.mAccessCount != null) {
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- getOrCreateAccessCount()[i] += other.mAccessCount[i];
- }
- }
- if (other.mRejectCount != null) {
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- getOrCreateRejectCount()[i] += other.mRejectCount[i];
- }
- }
- if (other.mAccessDuration != null) {
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- getOrCreateAccessDuration()[i] += other.mAccessDuration[i];
- }
- }
+ merge(this::getOrCreateAccessCount, other.mAccessCount);
+ merge(this::getOrCreateRejectCount, other.mRejectCount);
+ merge(this::getOrCreateAccessDuration, other.mAccessDuration);
}
- private void increaseAccessCount(@UidState int uidState, long increment) {
- getOrCreateAccessCount()[uidState] += increment;
+ private void increaseAccessCount(@UidState int uidState, @OpFlags int flags,
+ long increment) {
+ increaseCount(getOrCreateAccessCount(), uidState, flags, increment);
}
- private void increaseRejectCount(@UidState int uidState, long increment) {
- getOrCreateRejectCount()[uidState] += increment;
+ private void increaseRejectCount(@UidState int uidState, @OpFlags int flags,
+ long increment) {
+ increaseCount(getOrCreateRejectCount(), uidState, flags, increment);
}
- private void increaseAccessDuration(@UidState int uidState, long increment) {
- getOrCreateAccessDuration()[uidState] += increment;
+ private void increaseAccessDuration(@UidState int uidState, @OpFlags int flags,
+ long increment) {
+ increaseCount(getOrCreateAccessDuration(), uidState, flags, increment);
+ }
+
+ private void increaseCount(@NonNull LongSparseLongArray counts,
+ @UidState int uidState, @OpFlags int flags, long increment) {
+ while (flags != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(flags);
+ flags &= ~flag;
+ final long key = makeKey(uidState, flag);
+ counts.put(key, counts.get(key) + increment);
+ }
}
/**
@@ -3369,154 +3860,186 @@
/**
* Gets the number times the op was accessed (performed) in the foreground.
*
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
* @return The times the op was accessed in the foreground.
*
- * @see #getBackgroundAccessCount()
- * @see #getAccessCount(int)
+ * @see #getBackgroundAccessCount(int)
+ * @see #getAccessCount(int, int, int)
*/
- public long getForegroundAccessCount() {
- if (mAccessCount == null) {
- return 0;
- }
- return sum(mAccessCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
+ public long getForegroundAccessCount(@OpFlags int flags) {
+ return sumForFlagsInStates(mAccessCount, MAX_PRIORITY_UID_STATE,
+ resolveFirstUnrestrictedUidState(mOp), flags);
}
/**
* Gets the number times the op was accessed (performed) in the background.
*
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
* @return The times the op was accessed in the background.
*
- * @see #getForegroundAccessCount()
- * @see #getAccessCount(int)
+ * @see #getForegroundAccessCount(int)
+ * @see #getAccessCount(int, int, int)
*/
- public long getBackgroundAccessCount() {
- if (mAccessCount == null) {
- return 0;
- }
- return sum(mAccessCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
+ public long getBackgroundAccessCount(@OpFlags int flags) {
+ return sumForFlagsInStates(mAccessCount, resolveLastRestrictedUidState(mOp),
+ MIN_PRIORITY_UID_STATE, flags);
}
/**
- * Gets the number times the op was accessed (performed) for a given uid state.
+ * Gets the number times the op was accessed (performed) for a
+ * range of uid states.
*
- * @param uidState The UID state for which to query. Could be one of
+ * @param fromUidState The UID state from which to query. Could be one of
* {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
* {@link #UID_STATE_FOREGROUND_SERVICE_LOCATION},
* {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
* {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
+ * @param toUidState The UID state to which to query.
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
*
* @return The times the op was accessed for the given UID state.
*
- * @see #getForegroundAccessCount()
- * @see #getBackgroundAccessCount()
+ * @see #getForegroundAccessCount(int)
+ * @see #getBackgroundAccessCount(int)
*/
- public long getAccessCount(@UidState int uidState) {
- if (mAccessCount == null) {
- return 0;
- }
- return mAccessCount[uidState];
+ public long getAccessCount(@UidState int fromUidState, @UidState int toUidState,
+ @OpFlags int flags) {
+ return sumForFlagsInStates(mAccessCount, fromUidState, toUidState, flags);
}
/**
* Gets the number times the op was rejected in the foreground.
*
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
* @return The times the op was rejected in the foreground.
*
- * @see #getBackgroundRejectCount()
- * @see #getRejectCount(int)
+ * @see #getBackgroundRejectCount(int)
+ * @see #getRejectCount(int, int, int)
*/
- public long getForegroundRejectCount() {
- if (mRejectCount == null) {
- return 0;
- }
- return sum(mRejectCount, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
+ public long getForegroundRejectCount(@OpFlags int flags) {
+ return sumForFlagsInStates(mRejectCount, MAX_PRIORITY_UID_STATE,
+ resolveFirstUnrestrictedUidState(mOp), flags);
}
/**
* Gets the number times the op was rejected in the background.
*
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
* @return The times the op was rejected in the background.
*
- * @see #getForegroundRejectCount()
- * @see #getRejectCount(int)
+ * @see #getForegroundRejectCount(int)
+ * @see #getRejectCount(int, int, int)
*/
- public long getBackgroundRejectCount() {
- if (mRejectCount == null) {
- return 0;
- }
- return sum(mRejectCount, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
+ public long getBackgroundRejectCount(@OpFlags int flags) {
+ return sumForFlagsInStates(mRejectCount, resolveLastRestrictedUidState(mOp),
+ MIN_PRIORITY_UID_STATE, flags);
}
/**
- * Gets the number times the op was rejected for a given uid state.
+ * Gets the number times the op was rejected for a given range of UID states.
*
- * @param uidState The UID state for which to query. Could be one of
+ * @param fromUidState The UID state from which to query. Could be one of
* {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
* {@link #UID_STATE_FOREGROUND_SERVICE_LOCATION},
* {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
* {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
+ * @param toUidState The UID state to which to query.
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
*
* @return The times the op was rejected for the given UID state.
*
- * @see #getForegroundRejectCount()
- * @see #getBackgroundRejectCount()
+ * @see #getForegroundRejectCount(int)
+ * @see #getBackgroundRejectCount(int)
*/
- public long getRejectCount(@UidState int uidState) {
- if (mRejectCount == null) {
- return 0;
- }
- return mRejectCount[uidState];
+ public long getRejectCount(@UidState int fromUidState, @UidState int toUidState,
+ @OpFlags int flags) {
+ return sumForFlagsInStates(mRejectCount, fromUidState, toUidState, flags);
}
/**
* Gets the total duration the app op was accessed (performed) in the foreground.
*
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
* @return The total duration the app op was accessed in the foreground.
*
- * @see #getBackgroundAccessDuration()
- * @see #getAccessDuration(int)
+ * @see #getBackgroundAccessDuration(int)
+ * @see #getAccessDuration(int, int, int)
*/
- public long getForegroundAccessDuration() {
- if (mAccessDuration == null) {
- return 0;
- }
- return sum(mAccessDuration, UID_STATE_PERSISTENT, UID_STATE_LAST_NON_RESTRICTED + 1);
+ public long getForegroundAccessDuration(@OpFlags int flags) {
+ return sumForFlagsInStates(mAccessDuration, MAX_PRIORITY_UID_STATE,
+ resolveFirstUnrestrictedUidState(mOp), flags);
}
/**
* Gets the total duration the app op was accessed (performed) in the background.
*
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
* @return The total duration the app op was accessed in the background.
*
- * @see #getForegroundAccessDuration()
- * @see #getAccessDuration(int)
+ * @see #getForegroundAccessDuration(int)
+ * @see #getAccessDuration(int, int, int)
*/
- public long getBackgroundAccessDuration() {
- if (mAccessDuration == null) {
- return 0;
- }
- return sum(mAccessDuration, UID_STATE_LAST_NON_RESTRICTED + 1, _NUM_UID_STATE);
+ public long getBackgroundAccessDuration(@OpFlags int flags) {
+ return sumForFlagsInStates(mAccessDuration, resolveLastRestrictedUidState(mOp),
+ MIN_PRIORITY_UID_STATE, flags);
}
/**
- * Gets the total duration the app op was accessed (performed) for a given UID state.
+ * Gets the total duration the app op was accessed (performed) for a given
+ * range of UID states.
*
- * @param uidState The UID state for which to query. Could be one of
+ * @param fromUidState The UID state from which to query. Could be one of
* {@link #UID_STATE_PERSISTENT}, {@link #UID_STATE_TOP},
* {@link #UID_STATE_FOREGROUND_SERVICE_LOCATION},
* {@link #UID_STATE_FOREGROUND_SERVICE}, {@link #UID_STATE_FOREGROUND},
* {@link #UID_STATE_BACKGROUND}, {@link #UID_STATE_CACHED}.
+ * @param toUidState The UID state from which to query.
+ * @param flags The flags which are any combination of
+ * {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXY},
+ * {@link #OP_FLAG_UNTRUSTED_PROXY}, {@link #OP_FLAG_TRUSTED_PROXIED},
+ * {@link #OP_FLAG_UNTRUSTED_PROXIED}. You can use {@link #OP_FLAGS_ALL}
+ * for any flag.
*
* @return The total duration the app op was accessed for the given UID state.
*
- * @see #getForegroundAccessDuration()
- * @see #getBackgroundAccessDuration()
+ * @see #getForegroundAccessDuration(int)
+ * @see #getBackgroundAccessDuration(int)
*/
- public long getAccessDuration(@UidState int uidState) {
- if (mAccessDuration == null) {
- return 0;
- }
- return mAccessDuration[uidState];
+ public long getAccessDuration(@UidState int fromUidState, @UidState int toUidState,
+ @OpFlags int flags) {
+ return sumForFlagsInStates(mAccessDuration, fromUidState, toUidState, flags);
}
@Override
@@ -3527,80 +4050,11 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mOp);
- parcel.writeLongArray(mAccessCount);
- parcel.writeLongArray(mRejectCount);
- parcel.writeLongArray(mAccessDuration);
+ writeLongSparseLongArrayToParcel(mAccessCount, parcel);
+ writeLongSparseLongArrayToParcel(mRejectCount, parcel);
+ writeLongSparseLongArrayToParcel(mAccessDuration, parcel);
}
- private void accept(@NonNull HistoricalOpsVisitor visitor) {
- visitor.visitHistoricalOp(this);
- }
-
- private @NonNull long[] getOrCreateAccessCount() {
- if (mAccessCount == null) {
- mAccessCount = new long[_NUM_UID_STATE];
- }
- return mAccessCount;
- }
-
- private @NonNull long[] getOrCreateRejectCount() {
- if (mRejectCount == null) {
- mRejectCount = new long[_NUM_UID_STATE];
- }
- return mRejectCount;
- }
-
- private @NonNull long[] getOrCreateAccessDuration() {
- if (mAccessDuration == null) {
- mAccessDuration = new long[_NUM_UID_STATE];
- }
- return mAccessDuration;
- }
-
- /**
- *
- * Computes the sum given the start and end index.
- *
- * @param counts The data array.
- * @param start The start index (inclusive)
- * @param end The end index (exclusive)
- * @return The sum.
- */
- private static long sum(@NonNull long[] counts, int start, int end) {
- long totalCount = 0;
- for (int i = start; i < end; i++) {
- totalCount += counts[i];
- }
- return totalCount;
- }
-
- /**
- * Multiplies the entries in the array with the passed in scale factor and
- * rounds the result at up 0.5 boundary.
- *
- * @param data The data to scale.
- * @param scaleFactor The scale factor.
- */
- private static void scale(@NonNull long[] data, double scaleFactor) {
- if (data != null) {
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- data[i] = (long) HistoricalOps.round((double) data[i] * scaleFactor);
- }
- }
- }
-
- public static final @android.annotation.NonNull Creator<HistoricalOp> CREATOR = new Creator<HistoricalOp>() {
- @Override
- public @NonNull HistoricalOp createFromParcel(@NonNull Parcel source) {
- return new HistoricalOp(source);
- }
-
- @Override
- public @NonNull HistoricalOp[] newArray(int size) {
- return new HistoricalOp[size];
- }
- };
-
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -3613,23 +4067,201 @@
if (mOp != other.mOp) {
return false;
}
- if (!Arrays.equals(mAccessCount, other.mAccessCount)) {
+ if (!Objects.equals(mAccessCount, other.mAccessCount)) {
return false;
}
- if (!Arrays.equals(mRejectCount, other.mRejectCount)) {
+ if (!Objects.equals(mRejectCount, other.mRejectCount)) {
return false;
}
- return Arrays.equals(mAccessDuration, other.mAccessDuration);
+ return Objects.equals(mAccessDuration, other.mAccessDuration);
}
@Override
public int hashCode() {
int result = mOp;
- result = 31 * result + Arrays.hashCode(mAccessCount);
- result = 31 * result + Arrays.hashCode(mRejectCount);
- result = 31 * result + Arrays.hashCode(mAccessDuration);
+ result = 31 * result + Objects.hashCode(mAccessCount);
+ result = 31 * result + Objects.hashCode(mRejectCount);
+ result = 31 * result + Objects.hashCode(mAccessDuration);
return result;
}
+
+ private void accept(@NonNull HistoricalOpsVisitor visitor) {
+ visitor.visitHistoricalOp(this);
+ }
+
+ private @NonNull LongSparseLongArray getOrCreateAccessCount() {
+ if (mAccessCount == null) {
+ mAccessCount = new LongSparseLongArray();
+ }
+ return mAccessCount;
+ }
+
+ private @NonNull LongSparseLongArray getOrCreateRejectCount() {
+ if (mRejectCount == null) {
+ mRejectCount = new LongSparseLongArray();
+ }
+ return mRejectCount;
+ }
+
+ private @NonNull LongSparseLongArray getOrCreateAccessDuration() {
+ if (mAccessDuration == null) {
+ mAccessDuration = new LongSparseLongArray();
+ }
+ return mAccessDuration;
+ }
+
+ /**
+ * Multiplies the entries in the array with the passed in scale factor and
+ * rounds the result at up 0.5 boundary.
+ *
+ * @param data The data to scale.
+ * @param scaleFactor The scale factor.
+ */
+ private static void scale(@NonNull LongSparseLongArray data, double scaleFactor) {
+ if (data != null) {
+ final int size = data.size();
+ for (int i = 0; i < size; i++) {
+ data.put(data.keyAt(i), (long) HistoricalOps.round(
+ (double) data.valueAt(i) * scaleFactor));
+ }
+ }
+ }
+
+ /**
+ * Merges two arrays while lazily acquiring the destination.
+ *
+ * @param thisSupplier The destination supplier.
+ * @param other The array to merge in.
+ */
+ private static void merge(@NonNull Supplier<LongSparseLongArray> thisSupplier,
+ @Nullable LongSparseLongArray other) {
+ if (other != null) {
+ final int otherSize = other.size();
+ for (int i = 0; i < otherSize; i++) {
+ final LongSparseLongArray that = thisSupplier.get();
+ final long otherKey = other.keyAt(i);
+ final long otherValue = other.valueAt(i);
+ that.put(otherKey, that.get(otherKey) + otherValue);
+ }
+ }
+ }
+
+ /** @hide */
+ public @Nullable LongSparseArray<Object> collectKeys() {
+ LongSparseArray<Object> result = AppOpsManager.collectKeys(mAccessCount,
+ null /*result*/);
+ result = AppOpsManager.collectKeys(mRejectCount, result);
+ result = AppOpsManager.collectKeys(mAccessDuration, result);
+ return result;
+ }
+
+ public static final @android.annotation.NonNull Creator<HistoricalOp> CREATOR =
+ new Creator<HistoricalOp>() {
+ @Override
+ public @NonNull HistoricalOp createFromParcel(@NonNull Parcel source) {
+ return new HistoricalOp(source);
+ }
+
+ @Override
+ public @NonNull HistoricalOp[] newArray(int size) {
+ return new HistoricalOp[size];
+ }
+ };
+ }
+
+ /**
+ * Computes the sum of the counts for the given flags in between the begin and
+ * end UID states.
+ *
+ * @param counts The data array.
+ * @param beginUidState The beginning UID state (exclusive).
+ * @param endUidState The end UID state.
+ * @param flags The UID flags.
+ * @return The sum.
+ */
+ private static long sumForFlagsInStates(@Nullable LongSparseLongArray counts,
+ @UidState int beginUidState, @UidState int endUidState, @OpFlags int flags) {
+ if (counts == null) {
+ return 0;
+ }
+ long sum = 0;
+ while (flags != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(flags);
+ flags &= ~flag;
+ for (int uidState : UID_STATES) {
+ if (uidState < beginUidState || uidState > endUidState) {
+ continue;
+ }
+ final long key = makeKey(uidState, flag);
+ sum += counts.get(key);
+ }
+ }
+ return sum;
+ }
+
+ /**
+ * Finds the first non-negative value for the given flags in between the begin and
+ * end UID states.
+ *
+ * @param counts The data array.
+ * @param flags The UID flags.
+ * @param beginUidState The beginning UID state (exclusive).
+ * @param endUidState The end UID state.
+ * @return The non-negative value or -1.
+ */
+ private static long findFirstNonNegativeForFlagsInStates(@Nullable LongSparseLongArray counts,
+ @OpFlags int flags, @UidState int beginUidState, @UidState int endUidState) {
+ if (counts == null) {
+ return -1;
+ }
+ while (flags != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(flags);
+ flags &= ~flag;
+ for (int uidState : UID_STATES) {
+ if (uidState < beginUidState || uidState > endUidState) {
+ continue;
+ }
+ final long key = makeKey(uidState, flag);
+ final long value = counts.get(key);
+ if (value >= 0) {
+ return value;
+ }
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Finds the first non-null value for the given flags in between the begin and
+ * end UID states.
+ *
+ * @param counts The data array.
+ * @param flags The UID flags.
+ * @param beginUidState The beginning UID state (exclusive).
+ * @param endUidState The end UID state.
+ * @return The non-negative value or -1.
+ */
+ private static @Nullable String findFirstNonNullForFlagsInStates(
+ @Nullable LongSparseArray<String> counts, @OpFlags int flags,
+ @UidState int beginUidState, @UidState int endUidState) {
+ if (counts == null) {
+ return null;
+ }
+ while (flags != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(flags);
+ flags &= ~flag;
+ for (int uidState : UID_STATES) {
+ if (uidState < beginUidState || uidState > endUidState) {
+ continue;
+ }
+ final long key = makeKey(uidState, flag);
+ final String value = counts.get(key);
+ if (value != null) {
+ return value;
+ }
+ }
+ }
+ return null;
}
/**
@@ -3800,7 +4432,7 @@
Preconditions.checkNotNull(callback, "callback cannot be null");
try {
mService.getHistoricalOps(request.mUid, request.mPackageName, request.mOpNames,
- request.mBeginTimeMillis, request.mEndTimeMillis,
+ request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
new RemoteCallback((result) -> {
final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
final long identity = Binder.clearCallingIdentity();
@@ -3840,7 +4472,7 @@
try {
mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
request.mOpNames, request.mBeginTimeMillis, request.mEndTimeMillis,
- new RemoteCallback((result) -> {
+ request.mFlags, new RemoteCallback((result) -> {
final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
final long identity = Binder.clearCallingIdentity();
try {
@@ -4310,7 +4942,20 @@
* Like {@link #checkOp} but returns the <em>raw</em> mode associated with the op.
* Does not throw a security exception, does not translate {@link #MODE_FOREGROUND}.
*/
- public int unsafeCheckOpRaw(String op, int uid, String packageName) {
+ public int unsafeCheckOpRaw(@NonNull String op, int uid, String packageName) {
+ try {
+ return mService.checkOperationRaw(strOpToOp(op), uid, packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Like {@link #unsafeCheckOpNoThrow(String, int, String)} but returns the <em>raw</em>
+ * mode associated with the op. Does not throw a security exception, does not translate
+ * {@link #MODE_FOREGROUND}.
+ */
+ public int unsafeCheckOpRawNoThrow(@NonNull String op, int uid, @NonNull String packageName) {
try {
return mService.checkOperationRaw(strOpToOp(op), uid, packageName);
} catch (RemoteException e) {
@@ -4899,16 +5544,110 @@
}
/**
- * @hide
+ * Computes the max for the given flags in between the begin and
+ * end UID states.
+ *
+ * @param counts The data array.
+ * @param flags The UID flags.
+ * @param beginUidState The beginning UID state (exclusive).
+ * @param endUidState The end UID state.
+ * @return The sum.
*/
- public static long maxTime(long[] times, int start, int end) {
- long time = 0;
- for (int i = start; i < end; i++) {
- if (times[i] > time) {
- time = times[i];
+ private static long maxForFlagsInStates(@Nullable LongSparseLongArray counts,
+ @UidState int beginUidState, @UidState int endUidState,
+ @OpFlags int flags) {
+ if (counts == null) {
+ return 0;
+ }
+ long max = 0;
+ while (flags != 0) {
+ final int flag = 1 << Integer.numberOfTrailingZeros(flags);
+ flags &= ~flag;
+ for (int uidState : UID_STATES) {
+ if (uidState < beginUidState || uidState > endUidState) {
+ continue;
+ }
+ final long key = makeKey(uidState, flag);
+ max = Math.max(max, counts.get(key));
}
}
- return time;
+ return max;
+ }
+
+
+ private static void writeLongSparseLongArrayToParcel(
+ @Nullable LongSparseLongArray array, @NonNull Parcel parcel) {
+ if (array != null) {
+ final int size = array.size();
+ parcel.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ parcel.writeLong(array.keyAt(i));
+ parcel.writeLong(array.valueAt(i));
+ }
+ } else {
+ parcel.writeInt(-1);
+ }
+ }
+
+ private static @Nullable LongSparseLongArray readLongSparseLongArrayFromParcel(
+ @NonNull Parcel parcel) {
+ final int size = parcel.readInt();
+ if (size < 0) {
+ return null;
+ }
+ final LongSparseLongArray array = new LongSparseLongArray(size);
+ for (int i = 0; i < size; i++) {
+ array.append(parcel.readLong(), parcel.readLong());
+ }
+ return array;
+ }
+
+ private static void writeLongSparseStringArrayToParcel(
+ @Nullable LongSparseArray<String> array, @NonNull Parcel parcel) {
+ if (array != null) {
+ final int size = array.size();
+ parcel.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ parcel.writeLong(array.keyAt(i));
+ parcel.writeString(array.valueAt(i));
+ }
+ } else {
+ parcel.writeInt(-1);
+ }
+ }
+
+ private static @Nullable LongSparseArray<String> readLongSparseStringArrayFromParcel(
+ @NonNull Parcel parcel) {
+ final int size = parcel.readInt();
+ if (size < 0) {
+ return null;
+ }
+ final LongSparseArray<String> array = new LongSparseArray<>(size);
+ for (int i = 0; i < size; i++) {
+ array.append(parcel.readLong(), parcel.readString());
+ }
+ return array;
+ }
+
+ /**
+ * Collects the keys from an array to the result creating the result if needed.
+ *
+ * @param array The array whose keys to collect.
+ * @param result The optional result store collected keys.
+ * @return The result collected keys array.
+ */
+ private static LongSparseArray<Object> collectKeys(@Nullable LongSparseLongArray array,
+ @Nullable LongSparseArray<Object> result) {
+ if (array != null) {
+ if (result == null) {
+ result = new LongSparseArray<>();
+ }
+ final int accessSize = array.size();
+ for (int i = 0; i < accessSize; i++) {
+ result.put(array.keyAt(i), null);
+ }
+ }
+ return result;
}
/** @hide */
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
index 4a826d1..010a900 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 @@
* 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/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 65859c7..ad614b1 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -1,18 +1,37 @@
{
- "imports": [
- {
- "path": "frameworks/base/services/core/java/com/android/server/am"
- },
- {
- "path": "frameworks/base/services/core/java/com/android/server/wm"
- }
- ],
- "presubmit": [
- {
- "name": "CtsFragmentTestCases"
- },
- {
- "name": "CtsFragmentTestCasesSdk26"
- }
- ]
+ "imports": [
+ {
+ "path": "frameworks/base/services/core/java/com/android/server/am"
+ },
+ {
+ "path": "frameworks/base/services/core/java/com/android/server/wm"
+ }
+ ],
+ "presubmit": [
+ {
+ "name": "CtsFragmentTestCases"
+ },
+ {
+ "name": "CtsFragmentTestCasesSdk26"
+ },
+ {
+ "file_patterns": ["(/|^)AppOpsManager.java"],
+ "name": "CtsAppOpsTestCases"
+ },
+ {
+ "file_patterns": ["(/|^)AppOpsManager.java"],
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.appop.AppOpsUpgradeTest"
+ },
+ {
+ "include-filter": "com.android.server.appop.AppOpsServiceTest"
+ },
+ {
+ "include-filter": "com.android.server.appop.AppOpsActiveWatcherTest"
+ }
+ ]
+ }
+ ]
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d593ad1..efbd098 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3153,7 +3153,7 @@
* {@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 @@
* <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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* #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 @@
* <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 @@
* 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 @@
* 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 @@
* {@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 @@
* 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 @@
/**
* 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 @@
/**
* 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 @@
* <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 @@
* {@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 @@
* 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 @@
* 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 @@
* 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 1b50015..2051a55 100644
--- a/core/java/android/app/contentsuggestions/ClassificationsRequest.java
+++ b/core/java/android/app/contentsuggestions/ClassificationsRequest.java
@@ -54,10 +54,10 @@
}
/**
- * 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 @@
/**
* 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 @@
/**
* 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 257f98d..84f33b5 100644
--- a/core/java/android/app/contentsuggestions/SelectionsRequest.java
+++ b/core/java/android/app/contentsuggestions/SelectionsRequest.java
@@ -63,10 +63,10 @@
}
/**
- * 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl
index b72ec39..62b24e9 100644
--- a/core/java/android/app/usage/IUsageStatsManager.aidl
+++ b/core/java/android/app/usage/IUsageStatsManager.aidl
@@ -60,7 +60,7 @@
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 d34e6d3..cee6b87 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -35,6 +35,7 @@
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 @@
}
/**
+ * @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 @@
* @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 @@
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 2142cf3..3d1ddc3 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 @@
// 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 @@
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 @@
}
@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 @@
@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 38ea43e..0cc5f39 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -792,7 +792,7 @@
*
* @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 0304f19..b20cce9 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1343,6 +1343,7 @@
*/
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 a5464c2..c133fba 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -721,6 +721,7 @@
INSTALL_VIRTUAL_PRELOAD,
INSTALL_APEX,
INSTALL_ENABLE_ROLLBACK,
+ INSTALL_RESPECT_ALLOW_DOWNGRADE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface InstallFlags {}
@@ -865,6 +866,15 @@
*/
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 a25bbdb..9da8e4e 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -85,7 +85,8 @@
*
* @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 536c2e1..23401432 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -678,6 +678,31 @@
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 @@
}
}
+ 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 @@
}
}
+ @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 53d4dd3..bb0987d 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -89,7 +89,8 @@
*
* @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 @@
* @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 @@
* <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 @@
* <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 a17ebcb..eb0fe33 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -143,6 +143,7 @@
NET_CAPABILITY_NOT_CONGESTED,
NET_CAPABILITY_NOT_SUSPENDED,
NET_CAPABILITY_OEM_PAID,
+ NET_CAPABILITY_MCX
})
public @interface NetCapability { }
@@ -297,8 +298,14 @@
@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 @@
(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 @@
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 1bdfd94..a1f2430 100644
--- a/core/java/android/os/IncidentReportArgs.java
+++ b/core/java/android/os/IncidentReportArgs.java
@@ -36,6 +36,8 @@
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 @@
}
out.writeInt(mPrivacyPolicy);
+
+ out.writeString(mReceiverPkg);
+
+ out.writeString(mReceiverCls);
}
public void readFromParcel(Parcel in) {
@@ -91,6 +97,10 @@
}
mPrivacyPolicy = in.readInt();
+
+ mReceiverPkg = in.readString();
+
+ mReceiverCls = in.readString();
}
public static final @android.annotation.NonNull Parcelable.Creator<IncidentReportArgs> CREATOR
@@ -126,6 +136,8 @@
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 cb2517e..76e911d 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -40,6 +40,7 @@
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 9d58064..5695e42 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -476,6 +476,26 @@
}
/**
+ * 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 @@
}
}
}
+
+ /**
+ * 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 ee03689..d375c10 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -179,12 +179,21 @@
* @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 @@
}
@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 @@
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 d66789f..4fce14c 100644
--- a/core/java/android/permission/RuntimePermissionPresentationInfo.java
+++ b/core/java/android/permission/RuntimePermissionPresentationInfo.java
@@ -21,6 +21,8 @@
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 @@
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 @@
* @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 @@
mFlags = flags;
}
- private RuntimePermissionPresentationInfo(Parcel parcel) {
- mLabel = parcel.readCharSequence();
- mFlags = parcel.readInt();
- }
-
/**
* @return Whether the permission is granted.
*/
@@ -97,10 +96,14 @@
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 2cd3c48..5d4539c 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -64,12 +64,14 @@
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 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 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 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 @@
}
/**
- * 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 a34ac70..917b5c2 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -146,6 +146,8 @@
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 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 368fc2a..45219d6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3321,6 +3321,17 @@
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
diff --git a/core/java/android/service/carrier/ApnService.java b/core/java/android/service/carrier/ApnService.java
index d53eb37..57e4b1b 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 @@
};
@Override
- public IBinder onBind(Intent intent) {
+ @NonNull
+ public IBinder onBind(@Nullable Intent intent) {
return mBinder;
}
@@ -73,5 +76,6 @@
* subId.
*/
@WorkerThread
+ @NonNull
public abstract List<ContentValues> onRestoreApns(int subId);
}
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index 74e6c6e..7ef40cd 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 @@
/**
* 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 @@
* {@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 @@
/**
* 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 @@
/**
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* {@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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
/**
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* {@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 @@
* 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 c35d424..0000000
--- 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 10bfe63..0000000
--- 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
similarity index 82%
rename from core/java/android/service/textclassifier/ITextSelectionCallback.aidl
rename to core/java/android/service/textclassifier/ITextClassifierCallback.aidl
index 1b4c4d1..2926734 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 7941794..2f8d67b 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 @@
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 @@
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 263d99af..0000000
--- 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 235b8e8..4088ce8 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.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 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 @@
* </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 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");
- }
- }
+ mMainThreadHandler.post(() -> TextClassifierService.this.onSuggestSelection(
+ sessionId, request, mCancellationSignal, new ProxyCallback<>(callback)));
- @Override
- public void onFailure(CharSequence error) {
- try {
- if (callback.asBinder().isBinderAlive()) {
- callback.onFailure();
- }
- } catch (RemoteException e) {
- Slog.d(LOG_TAG, "Error calling 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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* instead
*/
@Deprecated
+ @MainThread
public void onSelectionEvent(
@Nullable TextClassificationSessionId sessionId, @NonNull SelectionEvent event) {}
@@ -396,6 +319,7 @@
* @param sessionId the session id
* @param event the TextClassifier event
*/
+ @MainThread
public void onTextClassifierEvent(
@Nullable TextClassificationSessionId sessionId, @NonNull TextClassifierEvent event) {}
@@ -405,6 +329,7 @@
* @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 @@
*
* @param sessionId the id of the session to destroy
*/
+ @MainThread
public void onDestroyTextClassificationSession(
@NonNull TextClassificationSessionId sessionId) {}
@@ -441,6 +367,11 @@
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 @@
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 a5d5af2..7fb0f95 100644
--- a/core/java/android/text/style/LineHeightSpan.java
+++ b/core/java/android/text/style/LineHeightSpan.java
@@ -88,7 +88,7 @@
/**
* 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/util/DocumentsStatsLog.java b/core/java/android/util/DocumentsStatsLog.java
index f483944..a67bbde 100644
--- a/core/java/android/util/DocumentsStatsLog.java
+++ b/core/java/android/util/DocumentsStatsLog.java
@@ -16,6 +16,7 @@
package android.util;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.provider.DocumentsContract;
import android.provider.DocumentsProvider;
@@ -126,7 +127,7 @@
*
* @param packageName
*/
- public static void logPickerLaunchedFrom(String packageName) {
+ public static void logPickerLaunchedFrom(@Nullable String packageName) {
StatsLog.write(StatsLog.DOCS_UI_PICKER_LAUNCHED_FROM_REPORTED, packageName);
}
diff --git a/core/java/android/util/LongSparseArray.java b/core/java/android/util/LongSparseArray.java
index 9ba0f5d..cf49803 100644
--- a/core/java/android/util/LongSparseArray.java
+++ b/core/java/android/util/LongSparseArray.java
@@ -21,6 +21,9 @@
import libcore.util.EmptyArray;
+import java.util.Arrays;
+import java.util.Objects;
+
/**
* SparseArray mapping longs to Objects. Unlike a normal array of Objects,
* there can be gaps in the indices. It is intended to be more memory efficient
diff --git a/core/java/android/util/LongSparseLongArray.java b/core/java/android/util/LongSparseLongArray.java
index af163ac..8dcdb40 100644
--- a/core/java/android/util/LongSparseLongArray.java
+++ b/core/java/android/util/LongSparseLongArray.java
@@ -22,6 +22,8 @@
import android.annotation.UnsupportedAppUsage;
import libcore.util.EmptyArray;
+import java.util.Arrays;
+
/**
* Map of {@code long} to {@code long}. Unlike a normal array of longs, there
* can be gaps in the indices. It is intended to be more memory efficient than using a
diff --git a/core/java/android/view/TEST_MAPPING b/core/java/android/view/TEST_MAPPING
new file mode 100644
index 0000000..87d428a
--- /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 877b304..874be81 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -18589,7 +18589,7 @@
@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 @@
* @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/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 86f85bf..b9dc0dd 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -24,7 +24,6 @@
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 @@
}
/**
- * 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 b273f7c..3e1e4ab 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 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 @@
*/
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 @@
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 @@
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 @@
private boolean mForEverything;
private ArrayList<LocusId> mLocusIds;
- private IntArray mRecursive;
+ private IntArray mFlags;
private boolean mDestroyed;
@@ -116,24 +132,24 @@
* 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 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 @@
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 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 @@
}
/**
- * 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 f859521..30938c1 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 @@
* @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 8b370f5..8f8766e 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -20,15 +20,14 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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");
+ BlockingCallback(String name) {
+ mReceiver = new ResponseReceiver<>(name);
+ }
@Override
- public void onSuccess(TextSelection selection) {
- mReceiver.onSuccess(selection);
+ public void onSuccess(Bundle result) {
+ mReceiver.onSuccess(TextClassifierService.getResponse(result));
}
@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 T get() {
+ return mReceiver.get();
}
- @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);
- }
-
- @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 73792b0..04bcb14 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -12744,7 +12744,7 @@
* 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/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a5a1dd9..67e0446 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1889,11 +1889,19 @@
* Set to true to reveal all service targets at once.
*/
public void setShowServiceTargets(boolean show) {
+ // mShowServiceTargets is only flipped once to show direct share targets. But after the
+ // initial display the list can be re-sorted and the user will see the target list
+ // change. This will log the initial show and the subsequent shuffle to help us get
+ // accurate timing of the UX.
+ if (show) {
+ getMetricsLogger().write(
+ new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN_DIRECT_TARGET)
+ .setSubtype(mShowServiceTargets ? MetricsEvent.PREVIOUSLY_VISIBLE
+ : MetricsEvent.PREVIOUSLY_HIDDEN));
+ }
if (show != mShowServiceTargets) {
mShowServiceTargets = show;
notifyDataSetChanged();
- getMetricsLogger().write(
- new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN_DIRECT_TARGET));
}
}
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index c096961..c4af4c7 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -48,9 +48,9 @@
@UnsupportedAppUsage
List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
void getHistoricalOps(int uid, String packageName, in List<String> ops, long beginTimeMillis,
- long endTimeMillis, in RemoteCallback callback);
+ long endTimeMillis, int flags, in RemoteCallback callback);
void getHistoricalOpsFromDiskRaw(int uid, String packageName, in List<String> ops,
- long beginTimeMillis, long endTimeMillis, in RemoteCallback callback);
+ long beginTimeMillis, long endTimeMillis, int flags, in RemoteCallback callback);
void offsetHistory(long duration);
void setHistoryParameters(int mode, long baseSnapshotInterval, int compressionStep);
void addHistoricalOps(in AppOpsManager.HistoricalOps ops);
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index f3bc2c7..445075d 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -616,7 +616,7 @@
// 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 @@
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 @@
// 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 e87295a..ae3e714 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4445,15 +4445,23 @@
@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"
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/layout/immersive_mode_cling.xml b/core/res/res/layout/immersive_mode_cling.xml
index b08b0f4..9fd615d 100644
--- a/core/res/res/layout/immersive_mode_cling.xml
+++ b/core/res/res/layout/immersive_mode_cling.xml
@@ -59,7 +59,7 @@
android:paddingStart="48dp"
android:paddingTop="40dp"
android:text="@string/immersive_cling_title"
- android:textColor="@color/primary_text_default_material_light"
+ android:textColor="@android:color/white"
android:textSize="24sp" />
<TextView
@@ -71,7 +71,7 @@
android:paddingStart="48dp"
android:paddingTop="12.6dp"
android:text="@string/immersive_cling_description"
- android:textColor="@color/primary_text_default_material_light"
+ android:textColor="@android:color/white"
android:textSize="16sp" />
<Button
@@ -89,4 +89,4 @@
android:textColor="@android:color/white"
android:textSize="14sp" />
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 47e5462..2f2fdca 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 426d813..d5444c0 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 6b0484e..faffc4b 100644
--- a/core/tests/BroadcastRadioTests/Android.mk
+++ b/core/tests/BroadcastRadioTests/Android.mk
@@ -25,7 +25,7 @@
# 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 69632c1..ebc6be7 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -92,7 +92,8 @@
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 =
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
index a5ac270..de2edc3 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 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 @@
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 2110a8f..3e53a38 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/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 7016cc7..2cf802b 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -59,6 +59,8 @@
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 @@
}
/**
+ * 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 42b6acd..0244942 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -62,7 +62,7 @@
*
* <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 @@
*
* <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 {
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 6ecb621..1894e32 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -581,9 +581,9 @@
* The default value for this property is {@code false}.
* <p>
* <strong>Note</strong>: This property corresponds to the
- * {@code android:useLevel} attribute on the inner {@code <gradient>}
+ * {@code android:useLevel} attribute on the inner {@code <gradient>}
* tag, NOT the {@code android:useLevel} attribute on the outer
- * {@code <shape>} tag. For example,
+ * {@code <shape>} tag. For example,
* <pre>{@code
* <shape ...>
* <gradient
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
index 596e5f5..99d3197 100644
--- a/keystore/tests/Android.mk
+++ b/keystore/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 hamcrest-library
LOCAL_PACKAGE_NAME := KeystoreTests
LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/keystore/tests/AndroidManifest.xml b/keystore/tests/AndroidManifest.xml
index 9bf2d0c..6833cd1 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 32f8ec4..fca2775 100644
--- a/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
+++ b/keystore/tests/src/android/security/ParcelableKeyGenParameterSpecTest.java
@@ -22,16 +22,20 @@
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 865cad4..b2edfd0 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.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 117d05e..d74f27c 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -1052,6 +1052,8 @@
}
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 0000000..d9f2acb
--- /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 5e8eac1..f056d3b 100644
--- a/libs/incident/include/android/os/IncidentReportArgs.h
+++ b/libs/incident/include/android/os/IncidentReportArgs.h
@@ -47,12 +47,16 @@
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 @@
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 06b7a5b..46c8dcf9 100644
--- a/libs/incident/src/IncidentReportArgs.cpp
+++ b/libs/incident/src/IncidentReportArgs.cpp
@@ -81,6 +81,16 @@
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 @@
}
mDest = dest;
+ mReceiverPkg = in->readString16();
+ mReceiverCls = in->readString16();
+
return OK;
}
@@ -161,6 +174,18 @@
}
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 ed74333..17e2509 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -113,10 +113,6 @@
* 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 @@
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 @@
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 @@
mProvider = null;
mTime = 0;
mElapsedRealtimeNanos = 0;
- mElapsedRealtimeUncertaintyNanos = 0;
mFieldsMask = 0;
mLatitude = 0;
mLongitude = 0;
@@ -595,37 +586,6 @@
}
/**
- * 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 @@
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 @@
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 @@
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 cd36414..9209ca9 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 @@
* 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 @@
* @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 @@
* @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 1afcd20..6515bd6 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 @@
* @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 7fc6f79..e6fd120 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 @@
* 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 @@
* @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 e29bd00..4b70367 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 @@
* 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 @@
* @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 fc0f08e..ff0d43e 100644
--- a/media/apex/java/android/media/MediaItem2.java
+++ b/media/apex/java/android/media/MediaItem2.java
@@ -245,7 +245,7 @@
/**
* 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 ef30172..f6b2031 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -344,7 +344,7 @@
* 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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
*/
// 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 @@
* 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 @@
* 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 @@
*/
// 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 @@
*/
// 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 @@
* notification {@code EventCallback.onVideoSizeChanged} when the size
* is available.
*/
- public Size getVideoSize() {
+ public @NonNull Size getVideoSize() {
return mVideoSize;
}
@@ -1560,7 +1561,7 @@
*
* 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 @@
*/
// 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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* 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 @@
* 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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 @@
*/
// 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 4eb9e8d..c0b3c82 100644
--- a/media/apex/java/android/media/UriDataSourceDesc.java
+++ b/media/apex/java/android/media/UriDataSourceDesc.java
@@ -51,7 +51,7 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* @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 @@
* @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 46d4204..aed8e4e 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -630,7 +630,7 @@
* 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 15f9b47..669baea 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4068,6 +4068,10 @@
/**
* 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 @@
* {@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 @@
* {@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 9a16aea..333cd2d 100644
--- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -72,7 +72,7 @@
*
* @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 @@
* @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 @@
*
* @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 @@
* @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 @@
*
* @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 @@
*
* @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 3d5120f..28937a6 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -618,7 +618,7 @@
* @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 @@
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/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 3bb696b..7cfe0dd 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -3168,7 +3168,8 @@
* @param sizeInFrames the number of frames available to write without blocking.
* Note that the frame size of a compressed stream is 1 byte.
*/
- public void onDataRequest(@NonNull AudioTrack track, int sizeInFrames) { }
+ public void onDataRequest(@NonNull AudioTrack track, @IntRange(from = 0) int sizeInFrames) {
+ }
}
/**
diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java
index 8bdb8a6..d9be0a5 100644
--- a/media/java/android/media/HwAudioSource.java
+++ b/media/java/android/media/HwAudioSource.java
@@ -165,7 +165,7 @@
* 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 1b82fcc..0285667 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -228,10 +228,10 @@
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 03e454c..da3362a 100644
--- a/media/java/android/media/MediaTimestamp.java
+++ b/media/java/android/media/MediaTimestamp.java
@@ -134,7 +134,7 @@
* @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 fbe5152..b302b06 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -571,13 +571,12 @@
// 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 852babe..31622a9 100644
--- a/media/java/android/media/SubtitleData.java
+++ b/media/java/android/media/SubtitleData.java
@@ -155,7 +155,7 @@
* @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 2a89888..990760c 100644
--- a/media/java/android/media/TimedMetaData.java
+++ b/media/java/android/media/TimedMetaData.java
@@ -104,7 +104,7 @@
* @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 98b6d97..c305b68 100644
--- a/media/java/android/media/audiopolicy/AudioProductStrategies.java
+++ b/media/java/android/media/audiopolicy/AudioProductStrategies.java
@@ -85,7 +85,7 @@
* 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 0b4ba93..b60947f 100644
--- a/media/java/android/media/audiopolicy/AudioVolumeGroup.java
+++ b/media/java/android/media/audiopolicy/AudioVolumeGroup.java
@@ -77,7 +77,7 @@
/**
* @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 301bec7..2e56f84 100644
--- a/media/java/android/media/audiopolicy/AudioVolumeGroups.java
+++ b/media/java/android/media/audiopolicy/AudioVolumeGroups.java
@@ -70,7 +70,7 @@
* 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 fb473f0..167d255 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -9,7 +9,7 @@
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 e50a375..fb2d630 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 204959f..132028c 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 d8c975f..87a59df 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 @@
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 feac63d..701454c 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.assertTrue;
import android.mtp.MtpConstants;
-import android.support.test.runner.AndroidJUnit4;
+
+import androidx.test.runner.AndroidJUnit4;
import libcore.net.MimeUtils;
diff --git a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
index 7755cbc..719417e 100644
--- a/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
+++ b/packages/DynamicAndroidInstallationService/src/com/android/dynandroid/DynamicAndroidInstallationService.java
@@ -114,6 +114,7 @@
private NotificationManager mNM;
private long mSystemSize;
+ private long mUserdataSize;
private long mInstalledSize;
private boolean mJustCancelledByUser;
@@ -220,9 +221,11 @@
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, userdata, mDynAndroid, this);
+ mInstallTask = new InstallationAsyncTask(
+ url, mSystemSize, mUserdataSize, mDynAndroid, this);
+
mInstallTask.execute();
// start fore ground
@@ -332,8 +335,8 @@
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 3c759e9..03fc773 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 @@
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 @@
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 @@
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 @@
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/SystemUI/res/drawable/ic_volume_remote.xml b/packages/SettingsLib/res/drawable/ic_volume_remote.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_volume_remote.xml
rename to 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
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_volume_remote_mute.xml
rename to packages/SettingsLib/res/drawable/ic_volume_remote_mute.xml
diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
index 4ac3ce4..09107ce 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationAccesses.java
@@ -48,6 +48,11 @@
// Keep last 24 hours of location app information.
private static final long RECENT_TIME_INTERVAL_MILLIS = DateUtils.DAY_IN_MILLIS;
+ /** The flags for querying ops that are trusted for showing in the UI. */
+ public static final int TRUSTED_STATE_FLAGS = AppOpsManager.OP_FLAG_SELF
+ | AppOpsManager.OP_FLAG_UNTRUSTED_PROXY
+ | AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
+
@VisibleForTesting
static final int[] LOCATION_OPS = new int[]{
AppOpsManager.OP_FINE_LOCATION,
@@ -136,8 +141,7 @@
// Earliest time for a location access to end and still be shown in list.
long recentLocationCutoffTime = now - RECENT_TIME_INTERVAL_MILLIS;
for (AppOpsManager.OpEntry entry : entries) {
- locationAccessFinishTime = Math.max(entry.getLastAccessBackgroundTime(),
- entry.getLastAccessForegroundTime());
+ locationAccessFinishTime = entry.getLastAccessTime(TRUSTED_STATE_FLAGS);
}
// Bail out if the entry is out of date.
if (locationAccessFinishTime < recentLocationCutoffTime) {
diff --git a/core/java/android/service/textclassifier/ITextLinksCallback.aidl b/packages/SettingsLib/src/com/android/settingslib/volume/D.java
similarity index 65%
rename from core/java/android/service/textclassifier/ITextLinksCallback.aidl
rename to packages/SettingsLib/src/com/android/settingslib/volume/D.java
index a9e0dde..7e0654d 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
similarity index 84%
rename from packages/SystemUI/src/com/android/systemui/volume/MediaSessions.java
rename to packages/SettingsLib/src/com/android/settingslib/volume/MediaSessions.java
index 8b00eee..4ed1154 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.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.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 @@
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 @@
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 @@
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 @@
if (appLabel.length() > 0) {
return appLabel;
}
- } catch (NameNotFoundException e) { }
+ } catch (NameNotFoundException e) {
+ }
return pkg;
}
@@ -240,29 +255,11 @@
}
}
- 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 @@
@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 @@
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 @@
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 0000000..4e770ae
--- /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/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
index d5b89ca..c1c5fa9 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
@@ -17,6 +17,7 @@
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.LongSparseLongArray;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -152,11 +153,12 @@
}
private OpEntry createOpEntryWithTime(int op, long time) {
- final long[] times = new long[AppOpsManager._NUM_UID_STATE];
// Slot for background access timestamp.
- times[AppOpsManager.UID_STATE_LAST_NON_RESTRICTED + 1] = time;
- final long[] rejectTimes = new long[AppOpsManager._NUM_UID_STATE];
- return new OpEntry(op, AppOpsManager.MODE_ALLOWED, times, rejectTimes, 0 /* duration */,
- 0 /* proxyUid */, "" /* proxyPackage */);
+ final LongSparseLongArray accessTimes = new LongSparseLongArray();
+ accessTimes.put(AppOpsManager.makeKey(AppOpsManager.UID_STATE_BACKGROUND,
+ AppOpsManager.OP_FLAG_SELF), time);
+
+ return new OpEntry(op, false, AppOpsManager.MODE_ALLOWED, accessTimes, null /*durations*/,
+ null /*rejectTimes*/, null /* proxyUids */, null /* proxyPackages */);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
index 08d5367..8bd5fd2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
@@ -17,6 +17,7 @@
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.LongSparseLongArray;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -153,6 +154,13 @@
}
private OpEntry createOpEntryWithTime(int op, long time, int duration) {
- return new OpEntry(op, AppOpsManager.MODE_ALLOWED, time, 0L, duration, 0, "");
+ final LongSparseLongArray accessTimes = new LongSparseLongArray();
+ accessTimes.put(AppOpsManager.makeKey(AppOpsManager.UID_STATE_TOP,
+ AppOpsManager.OP_FLAG_SELF), time);
+ final LongSparseLongArray durations = new LongSparseLongArray();
+ durations.put(AppOpsManager.makeKey(AppOpsManager.UID_STATE_TOP,
+ AppOpsManager.OP_FLAG_SELF), duration);
+ return new OpEntry(op, false, AppOpsManager.MODE_ALLOWED, accessTimes,
+ null /*rejectTimes*/, durations, null /* proxyUids */, null /* proxyPackages */);
}
}
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_preview.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_preview.png
deleted file mode 100644
index 035a4df..0000000
--- a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/default_preview.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml b/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml
index cdad94b..8dcddc2 100644
--- a/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml
+++ b/packages/SystemUI/res/layout/screen_pinning_request_text_area.xml
@@ -31,7 +31,7 @@
android:paddingStart="48dp"
android:paddingTop="43dp"
android:text="@string/screen_pinning_title"
- android:textColor="@color/screen_pinning_primary_text"
+ android:textColor="@android:color/white"
android:textSize="24sp" />
<TextView
@@ -43,7 +43,7 @@
android:paddingStart="48dp"
android:paddingTop="12.6dp"
android:text="@string/screen_pinning_description"
- android:textColor="@color/screen_pinning_primary_text"
+ android:textColor="@android:color/white"
android:textSize="16sp" />
<Button
diff --git a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl
index 586cdf3..716e127 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/res/values/internal.xml b/packages/SystemUI/res/values/internal.xml
index e0d3cd2..930cfce 100644
--- a/packages/SystemUI/res/values/internal.xml
+++ b/packages/SystemUI/res/values/internal.xml
@@ -18,6 +18,5 @@
<dimen name="status_bar_height">@*android:dimen/status_bar_height</dimen>
<dimen name="navigation_bar_height">@*android:dimen/navigation_bar_height</dimen>
<dimen name="navigation_bar_height_car_mode">@*android:dimen/navigation_bar_height_car_mode</dimen>
- <color name="screen_pinning_primary_text">@*android:color/primary_text_default_material_light</color>
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 563b007..d40fa66 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.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 @@
Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
Dependency.get(SysuiColorExtractor.class)
.removeOnColorsChangedListener(mColorsListener);
+ setClockPlugin(null);
}
private void setClockPlugin(ClockPlugin plugin) {
@@ -332,6 +337,19 @@
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 @@
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 2040a76..8ebe1ae 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.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 @@
if (mContentChangeListener != null) {
mContentChangeListener.run();
}
+ Trace.endSection();
return;
}
@@ -375,6 +378,17 @@
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 17546c5..808e264 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.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 @@
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/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
index 19d85b1..a313336 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 @@
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 @@
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 @@
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 @@
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 991b116..7295008 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 @@
@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 0000000..d7a2d9a
--- /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 12a8f0a..0000000
--- 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 0000000..dca0d45
--- /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 fdb0b36..41bcab5 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 @@
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 @@
private SystemUIDialog mHighTempDialog;
private SystemUIDialog mThermalShutdownDialog;
@VisibleForTesting SystemUIDialog mUsbHighTempDialog;
+ private BatteryStateSnapshot mCurrentBatterySnapshot;
/**
*/
@@ -195,17 +192,8 @@
}
@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 @@
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 @@
}
// 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 @@
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 e27c25e..1863860 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.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 @@
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 @@
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 @@
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 @@
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 @@
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,53 +266,150 @@
}
}
- 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();
- if (hybridEnabled) {
- Estimate estimate = mLastEstimate;
- if (estimate == null || mBatteryLevel != oldBatteryLevel) {
- estimate = mEnhancedEstimates.getEstimate();
- mLastEstimate = estimate;
- }
- // 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());
+ final boolean isPowerSaverMode = mPowerManager.isPowerSaveMode();
- // 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;
- }
+ // 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) {
+ if (DEBUG) {
+ Slog.d(TAG, "using hybrid");
+ }
+ 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]);
+ }
+
+ 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");
}
}
- if (shouldShowLowBatteryWarning(plugged, oldPlugged, oldBucket, bucket,
- mTimeRemaining, isPowerSaver, mBatteryStatus)) {
- mWarnings.showLowBatteryWarning(playSound);
+ 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 (shouldDismissLowBatteryWarning(plugged, oldBucket, bucket, mTimeRemaining,
- isPowerSaver)) {
+
+ } else if (shouldDismissHybridWarning(currentSnapshot)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Dismissing warning");
+ }
+ mWarnings.dismissLowBatteryWarning();
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Updating warning");
+ }
+ mWarnings.updateLowBatteryWarning();
+ }
+ }
+
+ @VisibleForTesting
+ 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;
+ }
+
+ // Only show the low warning once per charge cycle & no battery saver
+ 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
+ && (snapshot.getTimeRemainingMillis() < snapshot.getSevereThresholdMillis()
+ || snapshot.getBatteryLevel() <= snapshot.getSevereLevelThreshold());
+
+ final boolean canShow = canShowWarning || canShowSevereWarning;
+ if (DEBUG) {
+ Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith battery snapshot:"
+ + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle
+ + " mSevereWarningShownThisChargeCycle: " + mSevereWarningShownThisChargeCycle
+ + "\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();
@@ -311,64 +417,25 @@
}
@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;
+ 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(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) {
- 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);
-
- // Only show the severe warning once per charge cycle
- final boolean canShowSevereWarning = !mSevereWarningShownThisChargeCycle
- && (timeRemaining < mEnhancedEstimates.getSevereWarningThreshold()
- || mBatteryLevel <= critLevel);
-
- final boolean canShow = canShowWarning || canShowSevereWarning;
- if (DEBUG) {
- Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith values: "
- + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle
- + " mSevereWarningShownThisChargeCycle: " + mSevereWarningShownThisChargeCycle
- + " mEnhancedEstimates.timeremaining: " + timeRemaining
- + " mBatteryLevel: " + mBatteryLevel
- + " canShowWarning: " + canShowWarning
- + " canShowSevereWarning: " + canShowSevereWarning
- + " plugged: " + plugged
- + " batteryStatus: " + batteryStatus
- + " isPowerSaver: " + isPowerSaver);
- }
- return canShowWarning || canShowSevereWarning;
+ boolean shouldDismissLowBatteryWarning(
+ BatteryStateSnapshot currentSnapshot,
+ BatteryStateSnapshot lastSnapshot) {
+ return currentSnapshot.isPowerSaver()
+ || currentSnapshot.getPlugged()
+ || (currentSnapshot.getBucket() > lastSnapshot.getBucket()
+ && currentSnapshot.getBucket() > 0);
}
private void initTemperature() {
@@ -453,13 +520,21 @@
mWarnings.dump(pw);
}
+ /**
+ * The interface to allow PowerUI to communicate with whatever implementation of WarningsUI
+ * is being used by the system.
+ */
public interface WarningsUI {
+
+ /**
+ * 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 updateEstimate(Estimate estimate);
-
- void updateThresholds(long lowThreshold, long severeThreshold);
-
void dismissLowBatteryWarning();
void showLowBatteryWarning(boolean playSound);
@@ -486,6 +561,12 @@
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 a354885..142f398 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.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 @@
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 af3c96f..3fa3e1a 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 @@
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 c6d6218..7edb5a5 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 @@
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;
+ 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);
- }
- 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 32bc01c..4c16297 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.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 5876ae1..58c9311 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 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 @@
// 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 0aed63d..f51e473 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 @@
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.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.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 @@
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 @@
}
@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;
+
+ mPowerUI.maybeShowHybridWarning(state.get(), lastState);
+
+ assertThat(mPowerUI.mLowWarningShownThisChargeCycle).isTrue();
+ assertThat(mPowerUI.mSevereWarningShownThisChargeCycle).isFalse();
+
+ // verify severe warning noticed this cycle
+ lastState = state.get();
+ state.mBatteryLevel = 1;
+ state.mTimeRemainingMillis = Duration.ofMinutes(10).toMillis();
+
+ mPowerUI.maybeShowHybridWarning(state.get(), lastState);
+
+ assertThat(mPowerUI.mLowWarningShownThisChargeCycle).isTrue();
+ assertThat(mPowerUI.mSevereWarningShownThisChargeCycle).isTrue();
+
+ // verify getting past threshold resets values
+ lastState = state.get();
+ state.mBatteryLevel = 100;
+ state.mTimeRemainingMillis = Duration.ofDays(1).toMillis();
+
+ mPowerUI.maybeShowHybridWarning(state.get(), lastState);
+
+ assertThat(mPowerUI.mLowWarningShownThisChargeCycle).isFalse();
+ assertThat(mPowerUI.mSevereWarningShownThisChargeCycle).isFalse();
}
@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);
+ public void testShouldShowHybridWarning_lowLevelWarning() {
mPowerUI.start();
+ mPowerUI.mLowWarningShownThisChargeCycle = false;
+ mPowerUI.mSevereWarningShownThisChargeCycle = false;
+ BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
- // 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);
+ // 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_showHybridOnly_returnsShow() {
- 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();
+ mPowerUI.mLowWarningShownThisChargeCycle = false;
+ mPowerUI.mSevereWarningShownThisChargeCycle = false;
+ BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
- // 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);
+ // 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_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;
+ public void testShouldDismissHybridWarning() {
mPowerUI.start();
+ BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
- // 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);
+ // 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_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();
-
- // 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);
- }
-
- @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);
- 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);
- }
-
- @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);
- 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);
- }
-
- @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);
- 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);
- }
-
- @Test
- public void testShouldShowLowBatteryWarning_onlyShowsOncePerChargeCycle() {
- 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_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
- 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);
-
- verify(mMockWarnings, never()).dismissLowBatteryWarning();
- }
-
- @Test
- public void testSevereWarning_countsAsLowAndSevere_WarningOnlyShownOnce() {
- 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);
- }
-
- @Test
- public void testMaybeShowBatteryWarning_onlyQueriesEstimateOnBatteryLevelChangeOrNull() {
+ 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(estimate);
- mPowerUI.mBatteryStatus = BatteryManager.BATTERY_HEALTH_GOOD;
+ mPowerUI.mBatteryLevel = 10;
- // we expect that the first time it will query even if the level is the same
+ // 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);
+
+ // Battery level changes so we update again
mPowerUI.mBatteryLevel = 9;
- mPowerUI.maybeShowBatteryWarning(OLD_BATTERY_LEVEL_NINE, UNPLUGGED, UNPLUGGED,
- ABOVE_WARNING_BUCKET, ABOVE_WARNING_BUCKET);
- verify(mEnhancedEstimates, times(1)).getEstimate();
+ refreshedEstimate = mPowerUI.refreshEstimateIfNeeded();
+ assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD);
+ }
- // 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();
+ @Test
+ public void testShouldShowStandardWarning() {
+ mPowerUI.start();
+ BatteryStateSnapshotWrapper state = new BatteryStateSnapshotWrapper();
+ state.mIsHybrid = false;
+ BatteryStateSnapshot lastState = state.get();
- // 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();
+ // 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 testShouldDismissStandardWarning() {
+ mPowerUI.start();
+ 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 @@
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 5a639b2..91b161d 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -253,6 +253,13 @@
MANAGED_PROFILE = 2;
}
+ // Subtypes for showing direct sharing targets
+ enum DirectShareTargetPreviousState {
+ PREVIOUSLY_UNKNOWN = 0;
+ PREVIOUSLY_HIDDEN = 1;
+ PREVIOUSLY_VISIBLE = 2;
+ }
+
// Known visual elements: views or controls.
enum View {
// Unknown view
@@ -7068,6 +7075,18 @@
// 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/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d2c39ea..da89116 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1575,8 +1575,7 @@
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 18c2722..d266635 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -38,9 +38,11 @@
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 @@
* opportunity to reset any settings depending on our rescue level.
*/
public static void onSettingsProviderPublished(Context context) {
+ handleNativeRescuePartyResets();
executeRescueLevel(context);
}
@@ -176,6 +179,13 @@
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/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index c8e8ef8..e28d484 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1727,7 +1727,8 @@
final List<AppOpsManager.PackageOps> pkgs = manager.getOpsForPackage(uid, packageName, ops);
for (AppOpsManager.PackageOps pkg : CollectionUtils.emptyIfNull(pkgs)) {
for (AppOpsManager.OpEntry op : CollectionUtils.emptyIfNull(pkg.getOps())) {
- maxTime = Math.max(maxTime, op.getLastAccessTime());
+ maxTime = Math.max(maxTime, op.getLastAccessTime(
+ AppOpsManager.OP_FLAGS_ALL_TRUSTED));
}
}
return maxTime;
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 545baa0..5cca159 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -594,8 +594,9 @@
if (mProcStatesCache.get(uid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)
> ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
&& !vib.isNotification() && !vib.isRingtone()) {
- Slog.e(TAG, "Ignoring incoming vibration as process with uid = "
- + uid + " is background");
+ Slog.e(TAG, "Ignoring incoming vibration as process with"
+ + " uid = " + uid + " is background,"
+ + " usage = " + AudioAttributes.usageToString(vib.usageHint));
return;
}
linkVibration(vib);
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index 8e2ca06..34fca23 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 @@
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 efb1c44..c1ed54e 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
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 fa9b79d..1352504 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 @@
}
splitReceivers.add(o);
receivers.remove(i);
- break;
} else {
i++;
}
@@ -350,6 +349,7 @@
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 894a704..194549f 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 @@
// 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 @@
* 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/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 70c28a8..ba7288e 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -16,6 +16,9 @@
package com.android.server.appop;
+import static android.app.AppOpsManager.MAX_PRIORITY_UID_STATE;
+import static android.app.AppOpsManager.MIN_PRIORITY_UID_STATE;
+import static android.app.AppOpsManager.OP_FLAGS_ALL;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
@@ -23,12 +26,12 @@
import static android.app.AppOpsManager.UID_STATE_FOREGROUND;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE;
import static android.app.AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION;
-import static android.app.AppOpsManager.UID_STATE_LAST_NON_RESTRICTED;
+import static android.app.AppOpsManager.UID_STATE_MAX_LAST_NON_RESTRICTED;
import static android.app.AppOpsManager.UID_STATE_PERSISTENT;
import static android.app.AppOpsManager.UID_STATE_TOP;
-import static android.app.AppOpsManager._NUM_UID_STATE;
import static android.app.AppOpsManager.modeToName;
import static android.app.AppOpsManager.opToName;
+import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
import android.Manifest;
import android.annotation.NonNull;
@@ -39,6 +42,9 @@
import android.app.AppOpsManager;
import android.app.AppOpsManager.HistoricalOps;
import android.app.AppOpsManager.HistoricalOpsRequest;
+import android.app.AppOpsManager.Mode;
+import android.app.AppOpsManager.OpEntry;
+import android.app.AppOpsManager.OpFlags;
import android.app.AppOpsManagerInternal;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
import android.content.BroadcastReceiver;
@@ -76,6 +82,8 @@
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.KeyValueListParser;
+import android.util.LongSparseArray;
+import android.util.LongSparseLongArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -164,36 +172,6 @@
UID_STATE_CACHED, // ActivityManager.PROCESS_STATE_NONEXISTENT
};
- static final String[] UID_STATE_NAMES = new String[] {
- "pers ", // UID_STATE_PERSISTENT
- "top ", // UID_STATE_TOP
- "fgsvcl", // UID_STATE_FOREGROUND_SERVICE_LOCATION
- "fgsvc", // UID_STATE_FOREGROUND_SERVICE
- "fg ", // UID_STATE_FOREGROUND
- "bg ", // UID_STATE_BACKGROUND
- "cch ", // UID_STATE_CACHED
- };
-
- static final String[] UID_STATE_TIME_ATTRS = new String[] {
- "tp", // UID_STATE_PERSISTENT
- "tt", // UID_STATE_TOP
- "tfsl", // UID_STATE_FOREGROUND_SERVICE_LOCATION
- "tfs", // UID_STATE_FOREGROUND_SERVICE
- "tf", // UID_STATE_FOREGROUND
- "tb", // UID_STATE_BACKGROUND
- "tc", // UID_STATE_CACHED
- };
-
- static final String[] UID_STATE_REJECT_ATTRS = new String[] {
- "rp", // UID_STATE_PERSISTENT
- "rt", // UID_STATE_TOP
- "rfsl", // UID_STATE_FOREGROUND_SERVICE_LOCATION
- "rfs", // UID_STATE_FOREGROUND_SERVICE
- "rf", // UID_STATE_FOREGROUND
- "rb", // UID_STATE_BACKGROUND
- "rc", // UID_STATE_CACHED
- };
-
Context mContext;
final AtomicFile mFile;
final Handler mHandler;
@@ -355,12 +333,14 @@
public boolean isDefault() {
return (pkgOps == null || pkgOps.isEmpty())
- && (opModes == null || opModes.size() <= 0);
+ && (opModes == null || opModes.size() <= 0)
+ && (state == UID_STATE_CACHED
+ && (pendingState == UID_STATE_CACHED));
}
- int evalMode(int mode) {
+ int evalMode(int op, int mode) {
if (mode == AppOpsManager.MODE_FOREGROUND) {
- return state <= UID_STATE_LAST_NON_RESTRICTED
+ return state <= AppOpsManager.resolveLastRestrictedUidState(op)
? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED;
}
return mode;
@@ -425,41 +405,121 @@
}
final static class Op {
+ int op;
+ boolean running;
final UidState uidState;
- final int uid;
- final String packageName;
- final int op;
- int proxyUid = -1;
- String proxyPackageName;
- int mode;
- int duration;
- long time[] = new long[_NUM_UID_STATE];
- long rejectTime[] = new long[_NUM_UID_STATE];
+ final @NonNull String packageName;
+
+ private @Mode int mode;
+ private @Nullable LongSparseLongArray mAccessTimes;
+ private @Nullable LongSparseLongArray mRejectTimes;
+ private @Nullable LongSparseLongArray mDurations;
+ private @Nullable LongSparseLongArray mProxyUids;
+ private @Nullable LongSparseArray<String> mProxyPackageNames;
+
int startNesting;
long startRealtime;
- Op(UidState _uidState, String _packageName, int _op) {
- uidState = _uidState;
- uid = _uidState.uid;
- packageName = _packageName;
- op = _op;
- mode = AppOpsManager.opToDefaultMode(op);
- }
-
- boolean hasAnyTime() {
- for (int i = 0; i < AppOpsManager._NUM_UID_STATE; i++) {
- if (time[i] != 0) {
- return true;
- }
- if (rejectTime[i] != 0) {
- return true;
- }
- }
- return false;
+ Op(UidState uidState, String packageName, int op) {
+ this.op = op;
+ this.uidState = uidState;
+ this.packageName = packageName;
+ this.mode = AppOpsManager.opToDefaultMode(op);
}
int getMode() {
- return uidState.evalMode(mode);
+ return mode;
+ }
+
+ int evalMode() {
+ return uidState.evalMode(op, mode);
+ }
+
+ /** @hide */
+ public void accessed(long time, int proxyUid, @Nullable String proxyPackageName,
+ @AppOpsManager.UidState int uidState, @OpFlags int flags) {
+ final long key = AppOpsManager.makeKey(uidState, flags);
+ if (mAccessTimes == null) {
+ mAccessTimes = new LongSparseLongArray();
+ }
+ mAccessTimes.put(key, time);
+ updateProxyState(key, proxyUid, proxyPackageName);
+ if (mDurations != null) {
+ mDurations.delete(key);
+ }
+ }
+
+ /** @hide */
+ public void rejected(long time, int proxyUid, @Nullable String proxyPackageName,
+ @AppOpsManager.UidState int uidState, @OpFlags int flags) {
+ final long key = AppOpsManager.makeKey(uidState, flags);
+ if (mRejectTimes == null) {
+ mRejectTimes = new LongSparseLongArray();
+ }
+ mRejectTimes.put(key, time);
+ updateProxyState(key, proxyUid, proxyPackageName);
+ if (mDurations != null) {
+ mDurations.delete(key);
+ }
+ }
+
+ /** @hide */
+ public void started(long time, @AppOpsManager.UidState int uidState, @OpFlags int flags) {
+ updateAccessTimeAndDuration(time, -1 /*duration*/, uidState, flags);
+ running = true;
+ }
+
+ /** @hide */
+ public void finished(long time, long duration, @AppOpsManager.UidState int uidState,
+ @OpFlags int flags) {
+ updateAccessTimeAndDuration(time, duration, uidState, flags);
+ running = false;
+ }
+
+ /** @hide */
+ public void running(long time, long duration, @AppOpsManager.UidState int uidState,
+ @OpFlags int flags) {
+ updateAccessTimeAndDuration(time, duration, uidState, flags);
+ }
+
+ /** @hide */
+ public void continuing(long duration, @AppOpsManager.UidState int uidState,
+ @OpFlags int flags) {
+ final long key = AppOpsManager.makeKey(uidState, flags);
+ if (mDurations == null) {
+ mDurations = new LongSparseLongArray();
+ }
+ mDurations.put(key, duration);
+ }
+
+ private void updateAccessTimeAndDuration(long time, long duration,
+ @AppOpsManager.UidState int uidState, @OpFlags int flags) {
+ final long key = AppOpsManager.makeKey(uidState, flags);
+ if (mAccessTimes == null) {
+ mAccessTimes = new LongSparseLongArray();
+ }
+ mAccessTimes.put(key, time);
+ if (mDurations == null) {
+ mDurations = new LongSparseLongArray();
+ }
+ mDurations.put(key, duration);
+ }
+
+ private void updateProxyState(long key, int proxyUid,
+ @Nullable String proxyPackageName) {
+ if (mProxyUids == null) {
+ mProxyUids = new LongSparseLongArray();
+ }
+ mProxyUids.put(key, proxyUid);
+ if (mProxyPackageNames == null) {
+ mProxyPackageNames = new LongSparseArray<>();
+ }
+ mProxyPackageNames.put(key, proxyPackageName);
+ }
+
+ boolean hasAnyTime() {
+ return (mAccessTimes != null && mAccessTimes.size() > 0)
+ || (mRejectTimes != null && mRejectTimes.size() > 0);
}
}
@@ -812,7 +872,7 @@
final int opCount = client.mStartedOps.size();
for (int j = opCount - 1; j >= 0; j--) {
final Op op = client.mStartedOps.get(j);
- if (uid == op.uid && packageName.equals(op.packageName)) {
+ if (uid == op.uidState.uid && packageName.equals(op.packageName)) {
finishOperationLocked(op, /*finishNested*/ true);
client.mStartedOps.remove(j);
if (op.startNesting <= 0) {
@@ -829,9 +889,9 @@
final int opCount = ops.size();
for (int i = 0; i < opCount; i++) {
final Op op = ops.valueAt(i);
- if (op.duration == -1) {
+ if (op.running) {
scheduleOpActiveChangedIfNeededLocked(
- op.op, op.uid, op.packageName, false);
+ op.op, op.uidState.uid, op.packageName, false);
}
}
}
@@ -854,7 +914,7 @@
if (uidState != null && uidState.pendingState != newState) {
final int oldPendingState = uidState.pendingState;
uidState.pendingState = newState;
- if (newState < uidState.state || newState <= UID_STATE_LAST_NON_RESTRICTED) {
+ if (newState < uidState.state || newState <= UID_STATE_MAX_LAST_NON_RESTRICTED) {
// We are moving to a more important state, or the new state is in the
// foreground, then always do it immediately.
commitUidPendingStateLocked(uidState);
@@ -880,8 +940,18 @@
for (int j = ops.size() - 1; j >= 0; j--) {
final Op op = ops.valueAt(j);
if (op.startNesting > 0) {
- op.time[oldPendingState] = now;
- op.time[newState] = now;
+ final long duration = SystemClock.elapsedRealtime()
+ - op.startRealtime;
+ // We don't support proxy long running ops (start/stop)
+ mHistoricalRegistry.increaseOpAccessDuration(op.op,
+ op.uidState.uid, op.packageName, oldPendingState,
+ AppOpsManager.OP_FLAG_SELF, duration);
+ // Finish the op in the old state
+ op.finished(now, duration, oldPendingState,
+ AppOpsManager.OP_FLAG_SELF);
+ // Start the op in the new state
+ op.startRealtime = now;
+ op.started(now, newState, AppOpsManager.OP_FLAG_SELF);
}
}
}
@@ -911,13 +981,7 @@
resOps = new ArrayList<>();
for (int j=0; j<pkgOps.size(); j++) {
Op curOp = pkgOps.valueAt(j);
- final boolean running = curOp.duration == -1;
- long duration = running
- ? (elapsedNow - curOp.startRealtime)
- : curOp.duration;
- resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
- curOp.rejectTime, (int) duration, running, curOp.proxyUid,
- curOp.proxyPackageName));
+ resOps.add(getOpEntryForResult(curOp, elapsedNow));
}
} else {
for (int j=0; j<ops.length; j++) {
@@ -926,13 +990,7 @@
if (resOps == null) {
resOps = new ArrayList<>();
}
- final boolean running = curOp.duration == -1;
- final long duration = running
- ? (elapsedNow - curOp.startRealtime)
- : curOp.duration;
- resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
- curOp.rejectTime, (int) duration, running, curOp.proxyUid,
- curOp.proxyPackageName));
+ resOps.add(getOpEntryForResult(curOp, elapsedNow));
}
}
}
@@ -947,8 +1005,7 @@
if (ops == null) {
resOps = new ArrayList<>();
for (int j=0; j<uidOps.size(); j++) {
- resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
- 0, 0, 0, -1, null));
+ resOps.add(new OpEntry(uidOps.keyAt(j), uidOps.valueAt(j)));
}
} else {
for (int j=0; j<ops.length; j++) {
@@ -957,14 +1014,27 @@
if (resOps == null) {
resOps = new ArrayList<>();
}
- resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
- 0, 0, 0, -1, null));
+ resOps.add(new OpEntry(uidOps.keyAt(j), uidOps.valueAt(j)));
}
}
}
return resOps;
}
+ private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op, long elapsedNow) {
+ if (op.running) {
+ op.continuing(elapsedNow - op.startRealtime,
+ op.uidState.state, AppOpsManager.OP_FLAG_SELF);
+ }
+ final OpEntry entry = new OpEntry(op.op, op.running, op.mode,
+ op.mAccessTimes != null ? op.mAccessTimes.clone() : null,
+ op.mRejectTimes != null ? op.mRejectTimes.clone() : null,
+ op.mDurations != null ? op.mDurations.clone() : null,
+ op.mProxyUids != null ? op.mProxyUids.clone() : null,
+ op.mProxyPackageNames != null ? op.mProxyPackageNames.clone() : null);
+ return entry;
+ }
+
@Override
public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
@@ -1026,13 +1096,14 @@
@Override
public void getHistoricalOps(int uid, @NonNull String packageName,
@Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
- @NonNull RemoteCallback callback) {
+ @OpFlags int flags, @NonNull RemoteCallback callback) {
// Use the builder to validate arguments.
- final HistoricalOpsRequest request = new HistoricalOpsRequest.Builder(
+ new HistoricalOpsRequest.Builder(
beginTimeMillis, endTimeMillis)
.setUid(uid)
.setPackageName(packageName)
.setOpNames(opNames)
+ .setFlags(flags)
.build();
Preconditions.checkNotNull(callback, "callback cannot be null");
@@ -1041,79 +1112,23 @@
final String[] opNamesArray = (opNames != null)
? opNames.toArray(new String[opNames.size()]) : null;
- if (mHistoricalRegistry.getMode() == AppOpsManager.HISTORICAL_MODE_DISABLED) {
- // TODO (bug:122218838): Remove once the feature fully enabled.
- getHistoricalPackagesOpsCompat(uid, packageName, opNamesArray, beginTimeMillis,
- endTimeMillis, callback);
- } else {
- // Must not hold the appops lock
- mHistoricalRegistry.getHistoricalOps(uid, packageName, opNamesArray,
- beginTimeMillis, endTimeMillis, callback);
- }
- }
- private void getHistoricalPackagesOpsCompat(int uid, @NonNull String packageName,
- @Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
- @NonNull RemoteCallback callback) {
- synchronized (AppOpsService.this) {
- final HistoricalOps ops = new HistoricalOps(beginTimeMillis, endTimeMillis);
- if (opNames == null) {
- opNames = AppOpsManager.getOpStrs();
- }
- final int uidStateCount = mUidStates.size();
- for (int uidIdx = 0; uidIdx < uidStateCount; uidIdx++) {
- final UidState uidState = mUidStates.valueAt(uidIdx);
- if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()
- || (uid != Process.INVALID_UID && uid != uidState.uid)) {
- continue;
- }
- final ArrayMap<String, Ops> packages = uidState.pkgOps;
- final int packageCount = packages.size();
- for (int pkgIdx = 0; pkgIdx < packageCount; pkgIdx++) {
- final Ops pkgOps = packages.valueAt(pkgIdx);
- if (packageName != null && !packageName.equals(pkgOps.packageName)) {
- continue;
- }
- final int opCount = opNames.length;
- for (int opIdx = 0; opIdx < opCount; opIdx++) {
- final String opName = opNames[opIdx];
- if (!ArrayUtils.contains(opNames, opName)) {
- continue;
- }
- final int opCode = AppOpsManager.strOpToOp(opName);
- final Op op = pkgOps.get(opCode);
- if (op == null) {
- continue;
- }
- final int stateCount = AppOpsManager._NUM_UID_STATE;
- for (int stateIdx = 0; stateIdx < stateCount; stateIdx++) {
- if (op.rejectTime[stateIdx] != 0) {
- ops.increaseRejectCount(opCode, uidState.uid,
- pkgOps.packageName, stateIdx, 1);
- } else if (op.time[stateIdx] != 0) {
- ops.increaseAccessCount(opCode, uidState.uid,
- pkgOps.packageName, stateIdx, 1);
- }
- }
- }
- }
- }
- final Bundle payload = new Bundle();
- payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, ops);
- callback.sendResult(payload);
- }
+ // Must not hold the appops lock
+ mHistoricalRegistry.getHistoricalOps(uid, packageName, opNamesArray,
+ beginTimeMillis, endTimeMillis, flags, callback);
}
@Override
public void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
@Nullable List<String> opNames, long beginTimeMillis, long endTimeMillis,
- @NonNull RemoteCallback callback) {
+ @OpFlags int flags, @NonNull RemoteCallback callback) {
// Use the builder to validate arguments.
- final HistoricalOpsRequest request = new HistoricalOpsRequest.Builder(
+ new HistoricalOpsRequest.Builder(
beginTimeMillis, endTimeMillis)
.setUid(uid)
.setPackageName(packageName)
.setOpNames(opNames)
+ .setFlags(flags)
.build();
Preconditions.checkNotNull(callback, "callback cannot be null");
@@ -1125,7 +1140,7 @@
// Must not hold the appops lock
mHistoricalRegistry.getHistoricalOpsFromDiskRaw(uid, packageName, opNamesArray,
- beginTimeMillis, endTimeMillis, callback);
+ beginTimeMillis, endTimeMillis, flags, callback);
}
@Override
@@ -1172,7 +1187,7 @@
}
}
- void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
+ private void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
if (callingPid == Process.myPid()) {
return;
}
@@ -1316,6 +1331,8 @@
return;
}
+ boolean scheduleWrite = false;
+
int numPkgs = pkgOps.size();
for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
Ops ops = pkgOps.valueAt(pkgNum);
@@ -1327,14 +1344,14 @@
int defaultMode = AppOpsManager.opToDefaultMode(code);
if (op.mode != defaultMode) {
- Slog.w(TAG, "resetting app-op mode for " + AppOpsManager.opToName(code) + " of "
- + pkgOps.keyAt(pkgNum));
-
op.mode = defaultMode;
-
- scheduleWriteLocked();
+ scheduleWrite = true;
}
}
+
+ if (scheduleWrite) {
+ scheduleWriteLocked();
+ }
}
}
@@ -1544,9 +1561,10 @@
curOp.mode = AppOpsManager.opToDefaultMode(curOp.op);
changed = true;
uidChanged = true;
- callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
+ final int uid = curOp.uidState.uid;
+ callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
mOpModeWatchers.get(curOp.op));
- callbacks = addCallbacks(callbacks, curOp.op, curOp.uid, packageName,
+ callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
mPackageModeWatchers.get(packageName));
if (!curOp.hasAnyTime()) {
pkgOps.removeAt(j);
@@ -1727,6 +1745,7 @@
private int checkOperationUnchecked(int code, int uid, String packageName,
boolean raw) {
synchronized (this) {
+ checkPackage(uid, packageName);
if (isOpRestrictedLocked(uid, code, packageName)) {
return AppOpsManager.MODE_IGNORED;
}
@@ -1735,13 +1754,13 @@
if (uidState != null && uidState.opModes != null
&& uidState.opModes.indexOfKey(code) >= 0) {
final int rawMode = uidState.opModes.get(code);
- return raw ? rawMode : uidState.evalMode(rawMode);
+ return raw ? rawMode : uidState.evalMode(code, rawMode);
}
Op op = getOpLocked(code, uid, packageName, false, true, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
- return op.mode;
+ return raw ? op.mode : op.evalMode();
}
}
@@ -1855,21 +1874,32 @@
String proxyPackageName, int proxiedUid, String proxiedPackageName) {
verifyIncomingUid(proxyUid);
verifyIncomingOp(code);
+
String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
if (resolveProxyPackageName == null) {
return AppOpsManager.MODE_IGNORED;
}
+
+ final boolean isProxyTrusted = mContext.checkPermission(
+ Manifest.permission.UPDATE_APP_OPS_STATS, -1, proxyUid)
+ == PackageManager.PERMISSION_GRANTED;
+
+ final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
+ : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
final int proxyMode = noteOperationUnchecked(code, proxyUid,
- resolveProxyPackageName, -1, null);
+ resolveProxyPackageName, Process.INVALID_UID, null, proxyFlags);
if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
return proxyMode;
}
+
String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
if (resolveProxiedPackageName == null) {
return AppOpsManager.MODE_IGNORED;
}
+ final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
+ : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
- proxyMode, resolveProxyPackageName);
+ proxyUid, resolveProxyPackageName, proxiedFlags);
}
@Override
@@ -1892,11 +1922,12 @@
if (resolvedPackageName == null) {
return AppOpsManager.MODE_IGNORED;
}
- return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
+ return noteOperationUnchecked(code, uid, resolvedPackageName, Process.INVALID_UID, null,
+ AppOpsManager.OP_FLAG_SELF);
}
private int noteOperationUnchecked(int code, int uid, String packageName,
- int proxyUid, String proxyPackageName) {
+ int proxyUid, String proxyPackageName, @OpFlags int flags) {
synchronized (this) {
final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */,
false /* uidMismatchExpected */);
@@ -1914,49 +1945,52 @@
return AppOpsManager.MODE_IGNORED;
}
final UidState uidState = ops.uidState;
- if (op.duration == -1) {
+ if (op.running) {
+ final OpEntry entry = new OpEntry(op.op, op.running, op.mode, op.mAccessTimes,
+ op.mRejectTimes, op.mDurations, op.mProxyUids, op.mProxyPackageNames);
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName
- + " code " + code + " time=" + op.time[uidState.state]
- + " duration=" + op.duration);
+ + " code " + code + " time=" + entry.getLastAccessTime(uidState.state,
+ uidState.state, flags) + " duration=" + entry.getLastDuration(
+ uidState.state, uidState.state, flags));
}
- op.duration = 0;
+
final int switchCode = AppOpsManager.opToSwitch(code);
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
- final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
+ final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
if (uidMode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
- op.rejectTime[uidState.state] = System.currentTimeMillis();
+ op.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName,
+ uidState.state, flags);
+ mHistoricalRegistry.incrementOpRejected(code, uid, packageName,
+ uidState.state, flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
- mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
- uidState.state);
return uidMode;
}
} else {
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- final int mode = switchOp.getMode();
- if (mode != AppOpsManager.MODE_ALLOWED) {
+ final int mode = switchOp.evalMode();
+ if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
- op.rejectTime[uidState.state] = System.currentTimeMillis();
- scheduleOpNotedIfNeededLocked(op.op, uid, packageName, mode);
- mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
- uidState.state);
+ op.rejected(System.currentTimeMillis(), proxyUid, proxyPackageName,
+ uidState.state, flags);
+ mHistoricalRegistry.incrementOpRejected(code, uid, packageName,
+ uidState.state, flags);
+ scheduleOpNotedIfNeededLocked(code, uid, packageName, mode);
return mode;
}
}
if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
+ " package " + packageName);
- op.time[uidState.state] = System.currentTimeMillis();
+ op.accessed(System.currentTimeMillis(), proxyUid, proxyPackageName,
+ uidState.state, flags);
mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
- uidState.state);
- op.rejectTime[uidState.state] = 0;
- op.proxyUid = proxyUid;
- op.proxyPackageName = proxyPackageName;
+ uidState.state, flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_ALLOWED);
return AppOpsManager.MODE_ALLOWED;
@@ -2080,29 +2114,34 @@
final UidState uidState = ops.uidState;
// If there is a non-default per UID policy (we set UID op mode only if
// non-default) it takes over, otherwise use the per package policy.
+ final int opCode = op.op;
if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) {
- final int uidMode = uidState.evalMode(uidState.opModes.get(switchCode));
+ final int uidMode = uidState.evalMode(code, uidState.opModes.get(switchCode));
if (uidMode != AppOpsManager.MODE_ALLOWED
&& (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) {
if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
- op.rejectTime[uidState.state] = System.currentTimeMillis();
- mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
- uidState.state);
+ // We don't support proxy long running ops (start/stop)
+ op.rejected(System.currentTimeMillis(), -1 /*proxyUid*/,
+ null /*proxyPackage*/, uidState.state, AppOpsManager.OP_FLAG_SELF);
+ mHistoricalRegistry.incrementOpRejected(opCode, uid, packageName,
+ uidState.state, AppOpsManager.OP_FLAG_SELF);
return uidMode;
}
} else {
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
- final int mode = switchOp.getMode();
+ final int mode = switchOp.evalMode();
if (mode != AppOpsManager.MODE_ALLOWED
&& (!startIfModeDefault || mode != AppOpsManager.MODE_DEFAULT)) {
if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
- op.rejectTime[uidState.state] = System.currentTimeMillis();
- mHistoricalRegistry.incrementOpRejected(op.op, uid, packageName,
- uidState.state);
+ // We don't support proxy long running ops (start/stop)
+ op.rejected(System.currentTimeMillis(), -1 /*proxyUid*/,
+ null /*proxyPackage*/, uidState.state, AppOpsManager.OP_FLAG_SELF);
+ mHistoricalRegistry.incrementOpRejected(opCode, uid, packageName,
+ uidState.state, AppOpsManager.OP_FLAG_SELF);
return mode;
}
}
@@ -2110,11 +2149,12 @@
+ " package " + resolvedPackageName);
if (op.startNesting == 0) {
op.startRealtime = SystemClock.elapsedRealtime();
- op.time[uidState.state] = System.currentTimeMillis();
- mHistoricalRegistry.incrementOpAccessedCount(op.op, uid, packageName,
- uidState.state);
- op.rejectTime[uidState.state] = 0;
- op.duration = -1;
+ // We don't support proxy long running ops (start/stop)
+ op.started(System.currentTimeMillis(), uidState.state,
+ AppOpsManager.OP_FLAG_SELF);
+ mHistoricalRegistry.incrementOpAccessedCount(opCode, uid, packageName,
+ uidState.state, AppOpsManager.OP_FLAG_SELF);
+
scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, true);
}
op.startNesting++;
@@ -2161,7 +2201,7 @@
} finally {
Binder.restoreCallingIdentity(identity);
}
- Slog.wtf(TAG, "Operation not started: uid=" + op.uid + " pkg="
+ Slog.wtf(TAG, "Operation not started: uid=" + op.uidState.uid + " pkg="
+ op.packageName + " op=" + AppOpsManager.opToName(op.op));
return;
}
@@ -2272,16 +2312,24 @@
}
void finishOperationLocked(Op op, boolean finishNested) {
+ final int opCode = op.op;
+ final int uid = op.uidState.uid;
if (op.startNesting <= 1 || finishNested) {
if (op.startNesting == 1 || finishNested) {
- op.duration = (int)(SystemClock.elapsedRealtime() - op.startRealtime);
- mHistoricalRegistry.increaseOpAccessDuration(op.op, op.uid, op.packageName,
- op.uidState.state, op.duration);
- op.time[op.uidState.state] = System.currentTimeMillis();
+ // We don't support proxy long running ops (start/stop)
+ final long duration = SystemClock.elapsedRealtime() - op.startRealtime;
+ op.finished(System.currentTimeMillis(), duration, op.uidState.state,
+ AppOpsManager.OP_FLAG_SELF);
+ mHistoricalRegistry.increaseOpAccessDuration(opCode, uid, op.packageName,
+ op.uidState.state, AppOpsManager.OP_FLAG_SELF, duration);
} else {
- Slog.w(TAG, "Finishing op nesting under-run: uid " + op.uid + " pkg "
- + op.packageName + " code " + op.op + " time=" + op.time
- + " duration=" + op.duration + " nesting=" + op.startNesting);
+ final OpEntry entry = new OpEntry(op.op, op.running, op.mode, op.mAccessTimes,
+ op.mRejectTimes, op.mDurations, op.mProxyUids, op.mProxyPackageNames);
+ Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg "
+ + op.packageName + " code " + opCode + " time="
+ + entry.getLastAccessTime(OP_FLAGS_ALL)
+ + " duration=" + entry.getLastDuration(MAX_PRIORITY_UID_STATE,
+ MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL) + " nesting=" + op.startNesting);
}
if (op.startNesting >= 1) {
op.uidState.startNesting -= op.startNesting;
@@ -2311,7 +2359,7 @@
throw new IllegalArgumentException("Bad operation #" + op);
}
- private UidState getUidStateLocked(int uid, boolean edit) {
+ private @NonNull UidState getUidStateLocked(int uid, boolean edit) {
UidState uidState = mUidStates.get(uid);
if (uidState == null) {
if (!edit) {
@@ -2335,8 +2383,8 @@
}
private void commitUidPendingStateLocked(UidState uidState) {
- final boolean lastForeground = uidState.state <= UID_STATE_LAST_NON_RESTRICTED;
- final boolean nowForeground = uidState.pendingState <= UID_STATE_LAST_NON_RESTRICTED;
+ final boolean lastForeground = uidState.state <= UID_STATE_MAX_LAST_NON_RESTRICTED;
+ final boolean nowForeground = uidState.pendingState <= UID_STATE_MAX_LAST_NON_RESTRICTED;
uidState.state = uidState.pendingState;
uidState.pendingStateCommitTime = 0;
if (uidState.hasForegroundWatchers && lastForeground != nowForeground) {
@@ -2345,7 +2393,15 @@
continue;
}
final int code = uidState.foregroundOps.keyAt(fgi);
-
+ // For location ops we consider fg state only if the fg service
+ // is of location type, for all other ops any fg service will do.
+ final long resolvedLastRestrictedUidState = resolveFirstUnrestrictedUidState(code);
+ final boolean resolvedLastFg = uidState.state <= resolvedLastRestrictedUidState;
+ final boolean resolvedNowBg = uidState.pendingState
+ <= resolvedLastRestrictedUidState;
+ if (resolvedLastFg == resolvedNowBg) {
+ continue;
+ }
final ArraySet<ModeCallback> callbacks = mOpModeWatchers.get(code);
if (callbacks != null) {
for (int cbi = callbacks.size() - 1; cbi >= 0; cbi--) {
@@ -2360,8 +2416,10 @@
if (uidState.pkgOps != null) {
for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
- if (doAllPackages || (op != null
- && op.mode == AppOpsManager.MODE_FOREGROUND)) {
+ if (op == null) {
+ continue;
+ }
+ if (doAllPackages || op.mode == AppOpsManager.MODE_FOREGROUND) {
mHandler.sendMessage(PooledLambda.obtainMessage(
AppOpsService::notifyOpChanged,
this, callback, code, uidState.uid,
@@ -2651,7 +2709,7 @@
final int idx = uidState.opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
if (idx >= 0) {
uidState.opModes.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
- uidState.opModes.valueAt(idx));
+ uidState.opModes.valueAt(idx));
}
}
if (uidState.pkgOps == null) {
@@ -2664,7 +2722,7 @@
final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
if (op != null && op.mode != AppOpsManager.opToDefaultMode(op.op)) {
final Op copy = new Op(op.uidState, op.packageName,
- AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
+ AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
copy.mode = op.mode;
ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
changed = true;
@@ -2692,7 +2750,7 @@
scheduleFastWriteLocked();
}
- void readUidOps(XmlPullParser parser) throws NumberFormatException,
+ private void readUidOps(XmlPullParser parser) throws NumberFormatException,
XmlPullParserException, IOException {
final int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
int outerDepth = parser.getDepth();
@@ -2720,8 +2778,8 @@
}
}
- void readPackage(XmlPullParser parser) throws NumberFormatException,
- XmlPullParserException, IOException {
+ private void readPackage(XmlPullParser parser)
+ throws NumberFormatException, XmlPullParserException, IOException {
String pkgName = parser.getAttributeValue(null, "n");
int outerDepth = parser.getDepth();
int type;
@@ -2742,9 +2800,10 @@
}
}
- void readUid(XmlPullParser parser, String pkgName) throws NumberFormatException,
- XmlPullParserException, IOException {
+ private void readUid(XmlPullParser parser, String pkgName)
+ throws NumberFormatException, XmlPullParserException, IOException {
int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
+ final UidState uidState = getUidStateLocked(uid, true);
String isPrivilegedString = parser.getAttributeValue(null, "p");
boolean isPrivileged = false;
if (isPrivilegedString == null) {
@@ -2774,113 +2833,73 @@
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
-
String tagName = parser.getName();
if (tagName.equals("op")) {
- UidState uidState = getUidStateLocked(uid, true);
- if (uidState.pkgOps == null) {
- uidState.pkgOps = new ArrayMap<>();
- }
-
- Op op = new Op(uidState, pkgName,
- Integer.parseInt(parser.getAttributeValue(null, "n")));
-
- for (int i = parser.getAttributeCount()-1; i >= 0; i--) {
- final String name = parser.getAttributeName(i);
- final String value = parser.getAttributeValue(i);
- switch (name) {
- case "m":
- op.mode = Integer.parseInt(value);
- break;
- case "d":
- op.duration = Integer.parseInt(value);
- break;
- case "pu":
- op.proxyUid = Integer.parseInt(value);
- break;
- case "pp":
- op.proxyPackageName = value;
- break;
- case "tp":
- op.time[AppOpsManager.UID_STATE_PERSISTENT] = Long.parseLong(value);
- break;
- case "tt":
- op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
- break;
- case "tfsl":
- op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION] =
- Long.parseLong(value);
- break;
- case "tfs":
- op.time[AppOpsManager.UID_STATE_FOREGROUND_SERVICE] =
- Long.parseLong(value);
- break;
- case "tf":
- op.time[AppOpsManager.UID_STATE_FOREGROUND] = Long.parseLong(value);
- break;
- case "tb":
- op.time[AppOpsManager.UID_STATE_BACKGROUND] = Long.parseLong(value);
- break;
- case "tc":
- op.time[AppOpsManager.UID_STATE_CACHED] = Long.parseLong(value);
- break;
- case "rp":
- op.rejectTime[AppOpsManager.UID_STATE_PERSISTENT] =
- Long.parseLong(value);
- break;
- case "rt":
- op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
- break;
- case "rfsl":
- op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION] =
- Long.parseLong(value);
- break;
- case "rfs":
- op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND_SERVICE] =
- Long.parseLong(value);
- break;
- case "rf":
- op.rejectTime[AppOpsManager.UID_STATE_FOREGROUND] =
- Long.parseLong(value);
- break;
- case "rb":
- op.rejectTime[AppOpsManager.UID_STATE_BACKGROUND] =
- Long.parseLong(value);
- break;
- case "rc":
- op.rejectTime[AppOpsManager.UID_STATE_CACHED] =
- Long.parseLong(value);
- break;
- case "t":
- // Backwards compat.
- op.time[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
- break;
- case "r":
- // Backwards compat.
- op.rejectTime[AppOpsManager.UID_STATE_TOP] = Long.parseLong(value);
- break;
- default:
- Slog.w(TAG, "Unknown attribute in 'op' tag: " + name);
- break;
- }
- }
-
- Ops ops = uidState.pkgOps.get(pkgName);
- if (ops == null) {
- ops = new Ops(pkgName, uidState, isPrivileged);
- uidState.pkgOps.put(pkgName, ops);
- }
- ops.put(op.op, op);
+ readOp(parser, uidState, pkgName, isPrivileged);
} else {
Slog.w(TAG, "Unknown element under <pkg>: "
+ parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
- UidState uidState = getUidStateLocked(uid, false);
- if (uidState != null) {
- uidState.evalForegroundOps(mOpModeWatchers);
+ uidState.evalForegroundOps(mOpModeWatchers);
+ }
+
+ private void readOp(XmlPullParser parser, @NonNull UidState uidState,
+ @NonNull String pkgName, boolean isPrivileged) throws NumberFormatException,
+ XmlPullParserException, IOException {
+ Op op = new Op(uidState, pkgName,
+ Integer.parseInt(parser.getAttributeValue(null, "n")));
+
+ final int mode = XmlUtils.readIntAttribute(parser, "m",
+ AppOpsManager.opToDefaultMode(op.op));
+ op.mode = mode;
+
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tagName = parser.getName();
+ if (tagName.equals("st")) {
+ final long key = XmlUtils.readLongAttribute(parser, "n");
+
+ final int flags = AppOpsManager.extractFlagsFromKey(key);
+ final int state = AppOpsManager.extractUidStateFromKey(key);
+
+ final long accessTime = XmlUtils.readLongAttribute(parser, "t", 0);
+ final long rejectTime = XmlUtils.readLongAttribute(parser, "r", 0);
+ final long accessDuration = XmlUtils.readLongAttribute(parser, "d", 0);
+ final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
+ final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", 0);
+
+ if (accessTime > 0) {
+ op.accessed(accessTime, proxyUid, proxyPkg, state, flags);
+ }
+ if (rejectTime > 0) {
+ op.rejected(rejectTime, proxyUid, proxyPkg, state, flags);
+ }
+ if (accessDuration > 0) {
+ op.running(accessTime, accessDuration, state, flags);
+ }
+ } else {
+ Slog.w(TAG, "Unknown element under <op>: "
+ + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
}
+
+ if (uidState.pkgOps == null) {
+ uidState.pkgOps = new ArrayMap<>();
+ }
+ Ops ops = uidState.pkgOps.get(pkgName);
+ if (ops == null) {
+ ops = new Ops(pkgName, uidState, isPrivileged);
+ uidState.pkgOps.put(pkgName, ops);
+ }
+ ops.put(op.op, op);
}
void writeState() {
@@ -2955,30 +2974,53 @@
if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
out.attribute(null, "m", Integer.toString(op.getMode()));
}
- for (int k = 0; k < _NUM_UID_STATE; k++) {
- final long time = op.getLastTimeFor(k);
- if (time != 0) {
- out.attribute(null, UID_STATE_TIME_ATTRS[k],
- Long.toString(time));
+
+ final LongSparseArray keys = op.collectKeys();
+ if (keys == null || keys.size() <= 0) {
+ continue;
+ }
+
+ final int keyCount = keys.size();
+ for (int k = 0; k < keyCount; k++) {
+ final long key = keys.keyAt(k);
+
+ final int uidState = AppOpsManager.extractUidStateFromKey(key);
+ final int flags = AppOpsManager.extractFlagsFromKey(key);
+
+ final long accessTime = op.getLastAccessTime(
+ uidState, uidState, flags);
+ final long rejectTime = op.getLastRejectTime(
+ uidState, uidState, flags);
+ final long accessDuration = op.getLastDuration(
+ uidState, uidState, flags);
+ final String proxyPkg = op.getProxyPackageName(uidState, flags);
+ final int proxyUid = op.getProxyUid(uidState, flags);
+
+ if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
+ && proxyPkg == null && proxyUid < 0) {
+ continue;
}
- final long rejectTime = op.getLastRejectTimeFor(k);
- if (rejectTime != 0) {
- out.attribute(null, UID_STATE_REJECT_ATTRS[k],
- Long.toString(rejectTime));
+
+ out.startTag(null, "st");
+ out.attribute(null, "n", Long.toString(key));
+ if (accessTime > 0) {
+ out.attribute(null, "t", Long.toString(accessTime));
}
+ if (rejectTime > 0) {
+ out.attribute(null, "r", Long.toString(rejectTime));
+ }
+ if (accessDuration > 0) {
+ out.attribute(null, "d", Long.toString(accessDuration));
+ }
+ if (proxyPkg != null) {
+ out.attribute(null, "pp", proxyPkg);
+ }
+ if (proxyUid >= 0) {
+ out.attribute(null, "pu", Integer.toString(proxyUid));
+ }
+ out.endTag(null, "st");
}
- int dur = op.getDuration();
- if (dur != 0) {
- out.attribute(null, "d", Integer.toString(dur));
- }
- int proxyUid = op.getProxyUid();
- if (proxyUid != -1) {
- out.attribute(null, "pu", Integer.toString(proxyUid));
- }
- String proxyPackageName = op.getProxyPackageName();
- if (proxyPackageName != null) {
- out.attribute(null, "pp", proxyPackageName);
- }
+
out.endTag(null, "op");
}
out.endTag(null, "uid");
@@ -3462,32 +3504,80 @@
pw.println(" Limit output to data associated with the given package name.");
pw.println(" --watchers");
pw.println(" Only output the watcher sections.");
+ pw.println(" --history");
+ pw.println(" Output the historical data.");
}
- private void dumpTimesLocked(PrintWriter pw, String firstPrefix, String prefix, long[] times,
- long now, SimpleDateFormat sdf, Date date) {
- boolean hasTime = false;
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- if (times[i] != 0) {
- hasTime = true;
- break;
- }
- }
- if (!hasTime) {
+ private void dumpStatesLocked(@NonNull PrintWriter pw, @NonNull Op op,
+ long now, @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
+
+ final OpEntry entry = new OpEntry(op.op, op.running, op.mode, op.mAccessTimes,
+ op.mRejectTimes, op.mDurations, op.mProxyUids, op.mProxyPackageNames);
+
+ final LongSparseArray keys = entry.collectKeys();
+ if (keys == null || keys.size() <= 0) {
return;
}
- boolean first = true;
- for (int i = 0; i < _NUM_UID_STATE; i++) {
- if (times[i] != 0) {
- pw.print(first ? firstPrefix : prefix);
- first = false;
- pw.print(UID_STATE_NAMES[i]);
- pw.print(" = ");
- date.setTime(times[i]);
+
+ final int keyCount = keys.size();
+ for (int k = 0; k < keyCount; k++) {
+ final long key = keys.keyAt(k);
+
+ final int uidState = AppOpsManager.extractUidStateFromKey(key);
+ final int flags = AppOpsManager.extractFlagsFromKey(key);
+
+ final long accessTime = entry.getLastAccessTime(
+ uidState, uidState, flags);
+ final long rejectTime = entry.getLastRejectTime(
+ uidState, uidState, flags);
+ final long accessDuration = entry.getLastDuration(
+ uidState, uidState, flags);
+ final String proxyPkg = entry.getProxyPackageName(uidState, flags);
+ final int proxyUid = entry.getProxyUid(uidState, flags);
+
+ if (accessTime > 0) {
+ pw.print(prefix);
+ pw.print("Access: ");
+ pw.print(AppOpsManager.keyToString(key));
+ pw.print(" ");
+ date.setTime(accessTime);
pw.print(sdf.format(date));
pw.print(" (");
- TimeUtils.formatDuration(times[i]-now, pw);
- pw.println(")");
+ TimeUtils.formatDuration(accessTime - now, pw);
+ pw.print(")");
+ if (accessDuration > 0) {
+ pw.print(" duration=");
+ TimeUtils.formatDuration(accessDuration, pw);
+ }
+ if (proxyUid >= 0) {
+ pw.print(" proxy[");
+ pw.print("uid=");
+ pw.print(proxyUid);
+ pw.print(", pkg=");
+ pw.print(proxyPkg);
+ pw.print("]");
+ }
+ pw.println();
+ }
+
+ if (rejectTime > 0) {
+ pw.print(prefix);
+ pw.print("Reject: ");
+ pw.print(AppOpsManager.keyToString(key));
+ date.setTime(rejectTime);
+ pw.print(sdf.format(date));
+ pw.print(" (");
+ TimeUtils.formatDuration(rejectTime - now, pw);
+ pw.print(")");
+ if (proxyUid >= 0) {
+ pw.print(" proxy[");
+ pw.print("uid=");
+ pw.print(proxyUid);
+ pw.print(", pkg=");
+ pw.print(proxyPkg);
+ pw.print("]");
+ }
+ pw.println();
}
}
}
@@ -3501,6 +3591,7 @@
int dumpUid = Process.INVALID_UID;
int dumpMode = -1;
boolean dumpWatchers = false;
+ boolean dumpHistory = false;
if (args != null) {
for (int i=0; i<args.length; i++) {
@@ -3550,6 +3641,8 @@
}
} else if ("--watchers".equals(arg)) {
dumpWatchers = true;
+ } else if ("--history".equals(arg)) {
+ dumpHistory = true;
} else if (arg.length() > 0 && arg.charAt(0) == '-'){
pw.println("Unknown option: " + arg);
return;
@@ -3562,7 +3655,9 @@
synchronized (this) {
pw.println("Current AppOps Service state:");
- mConstants.dump(pw);
+ if (!dumpHistory && !dumpWatchers) {
+ mConstants.dump(pw);
+ }
pw.println();
final long now = System.currentTimeMillis();
final long nowElapsed = SystemClock.elapsedRealtime();
@@ -3571,7 +3666,7 @@
final Date date = new Date();
boolean needSep = false;
if (dumpOp < 0 && dumpMode < 0 && dumpPackage == null && mProfileOwners != null
- && !dumpWatchers) {
+ && !dumpWatchers && !dumpHistory) {
pw.println(" Profile owners:");
for (int poi = 0; poi < mProfileOwners.size(); poi++) {
pw.print(" User #");
@@ -3582,7 +3677,7 @@
}
pw.println();
}
- if (mOpModeWatchers.size() > 0) {
+ if (mOpModeWatchers.size() > 0 && !dumpHistory) {
boolean printedHeader = false;
for (int i=0; i<mOpModeWatchers.size(); i++) {
if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
@@ -3612,7 +3707,7 @@
}
}
}
- if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
+ if (mPackageModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
boolean printedHeader = false;
for (int i=0; i<mPackageModeWatchers.size(); i++) {
if (dumpPackage != null && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
@@ -3632,7 +3727,7 @@
}
}
}
- if (mModeWatchers.size() > 0 && dumpOp < 0) {
+ if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
boolean printedHeader = false;
for (int i=0; i<mModeWatchers.size(); i++) {
final ModeCallback cb = mModeWatchers.valueAt(i);
@@ -3730,7 +3825,7 @@
pw.println(cb);
}
}
- if (mClients.size() > 0 && dumpMode < 0 && !dumpWatchers) {
+ if (mClients.size() > 0 && dumpMode < 0 && !dumpWatchers && !dumpHistory) {
needSep = true;
boolean printedHeader = false;
for (int i=0; i<mClients.size(); i++) {
@@ -3759,7 +3854,7 @@
pw.println(" Started ops:");
printedStarted = true;
}
- pw.print(" "); pw.print("uid="); pw.print(op.uid);
+ pw.print(" "); pw.print("uid="); pw.print(op.uidState.uid);
pw.print(" pkg="); pw.print(op.packageName);
pw.print(" op="); pw.println(AppOpsManager.opToName(op.op));
}
@@ -3767,7 +3862,7 @@
}
}
if (mAudioRestrictions.size() > 0 && dumpOp < 0 && dumpPackage != null
- && dumpMode < 0 && !dumpWatchers) {
+ && dumpMode < 0 && !dumpWatchers && !dumpWatchers) {
boolean printedHeader = false;
for (int o=0; o<mAudioRestrictions.size(); o++) {
final String op = AppOpsManager.opToName(mAudioRestrictions.keyAt(o));
@@ -3800,7 +3895,7 @@
final SparseIntArray opModes = uidState.opModes;
final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
- if (dumpWatchers) {
+ if (dumpWatchers || dumpHistory) {
continue;
}
if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
@@ -3847,10 +3942,10 @@
pw.print(" Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
pw.print(" state=");
- pw.println(UID_STATE_NAMES[uidState.state]);
+ pw.println(AppOpsManager.getUidStateName(uidState.state));
if (uidState.state != uidState.pendingState) {
pw.print(" pendingState=");
- pw.println(UID_STATE_NAMES[uidState.pendingState]);
+ pw.println(AppOpsManager.getUidStateName(uidState.pendingState));
}
if (uidState.pendingStateCommitTime != 0) {
pw.print(" pendingStateCommitTime=");
@@ -3906,7 +4001,8 @@
boolean printedPackage = false;
for (int j=0; j<ops.size(); j++) {
final Op op = ops.valueAt(j);
- if (dumpOp >= 0 && dumpOp != op.op) {
+ final int opCode = op.op;
+ if (dumpOp >= 0 && dumpOp != opCode) {
continue;
}
if (dumpMode >= 0 && dumpMode != op.mode) {
@@ -3916,32 +4012,23 @@
pw.print(" Package "); pw.print(ops.packageName); pw.println(":");
printedPackage = true;
}
- pw.print(" "); pw.print(AppOpsManager.opToName(op.op));
+ pw.print(" "); pw.print(AppOpsManager.opToName(opCode));
pw.print(" ("); pw.print(AppOpsManager.modeToName(op.mode));
- final int switchOp = AppOpsManager.opToSwitch(op.op);
- if (switchOp != op.op) {
+ final int switchOp = AppOpsManager.opToSwitch(opCode);
+ if (switchOp != opCode) {
pw.print(" / switch ");
pw.print(AppOpsManager.opToName(switchOp));
final Op switchObj = ops.get(switchOp);
- int mode = switchObj != null
- ? switchObj.mode : AppOpsManager.opToDefaultMode(switchOp);
+ int mode = switchObj != null ? switchObj.mode
+ : AppOpsManager.opToDefaultMode(switchOp);
pw.print("="); pw.print(AppOpsManager.modeToName(mode));
}
pw.println("): ");
- dumpTimesLocked(pw,
- " Access: ",
- " ", op.time, now, sdf, date);
- dumpTimesLocked(pw,
- " Reject: ",
- " ", op.rejectTime, now, sdf, date);
- if (op.duration == -1) {
+ dumpStatesLocked(pw, op, now, sdf, date, " ");
+ if (op.running) {
pw.print(" Running start at: ");
TimeUtils.formatDuration(nowElapsed-op.startRealtime, pw);
pw.println();
- } else if (op.duration != 0) {
- pw.print(" duration=");
- TimeUtils.formatDuration(op.duration, pw);
- pw.println();
}
if (op.startNesting != 0) {
pw.print(" startNesting=");
@@ -3960,7 +4047,7 @@
ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
boolean printedTokenHeader = false;
- if (dumpMode >= 0 || dumpWatchers) {
+ if (dumpMode >= 0 || dumpWatchers || dumpHistory) {
continue;
}
@@ -4044,7 +4131,9 @@
}
// Must not hold the appops lock
- mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpOp);
+ if (dumpHistory && !dumpWatchers) {
+ mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpOp);
+ }
}
private static final class Restriction {
@@ -4158,7 +4247,7 @@
final ClientState client = mClients.valueAt(i);
for (int j = client.mStartedOps.size() - 1; j >= 0; j--) {
final Op op = client.mStartedOps.get(j);
- if (op.op == code && op.uid == uid) return true;
+ if (op.op == code && op.uidState.uid == uid) return true;
}
}
}
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index 4485a54..280bc02 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -23,6 +23,7 @@
import android.app.AppOpsManager.HistoricalOps;
import android.app.AppOpsManager.HistoricalPackageOps;
import android.app.AppOpsManager.HistoricalUidOps;
+import android.app.AppOpsManager.OpFlags;
import android.app.AppOpsManager.UidState;
import android.content.ContentResolver;
import android.database.ContentObserver;
@@ -37,6 +38,7 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArraySet;
+import android.util.LongSparseArray;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.Xml;
@@ -297,20 +299,20 @@
}
}
- @Nullable void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
+ void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
@Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
- @NonNull RemoteCallback callback) {
+ @OpFlags int flags, @NonNull RemoteCallback callback) {
final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
- beginTimeMillis, endTimeMillis);
+ beginTimeMillis, endTimeMillis, flags);
final Bundle payload = new Bundle();
payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
callback.sendResult(payload);
}
- @Nullable void getHistoricalOps(int uid, @NonNull String packageName,
+ void getHistoricalOps(int uid, @NonNull String packageName,
@Nullable String[] opNames, long beginTimeMillis, long endTimeMillis,
- @NonNull RemoteCallback callback) {
+ @OpFlags int flags, @NonNull RemoteCallback callback) {
final long currentTimeMillis = System.currentTimeMillis();
if (endTimeMillis == Long.MAX_VALUE) {
endTimeMillis = currentTimeMillis;
@@ -326,6 +328,8 @@
synchronized (mOnDiskLock) {
final List<HistoricalOps> pendingWrites;
final HistoricalOps currentOps;
+ boolean collectOpsFromDisk;
+
synchronized (mInMemoryLock) {
currentOps = getUpdatedPendingHistoricalOpsMLocked(currentTimeMillis);
if (!(inMemoryAdjBeginTimeMillis >= currentOps.getEndTimeMillis()
@@ -338,10 +342,11 @@
}
pendingWrites = new ArrayList<>(mPendingWrites);
mPendingWrites.clear();
+ collectOpsFromDisk = inMemoryAdjEndTimeMillis > currentOps.getEndTimeMillis();
}
// If the query was only for in-memory state - done.
- if (inMemoryAdjEndTimeMillis > currentOps.getEndTimeMillis()) {
+ if (collectOpsFromDisk) {
// If there is a write in flight we need to force it now
persistPendingHistory(pendingWrites);
// Collect persisted state.
@@ -352,7 +357,7 @@
final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
- onDiskAndInMemoryOffsetMillis, 0);
mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, opNames,
- onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis);
+ onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis, flags);
}
// Rebase the result time to be since epoch.
@@ -366,32 +371,31 @@
}
void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
- @UidState int uidState) {
+ @UidState int uidState, @OpFlags int flags) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
- .increaseAccessCount(op, uid, packageName, uidState, 1);
-
+ .increaseAccessCount(op, uid, packageName, uidState, flags, 1);
}
}
}
void incrementOpRejected(int op, int uid, @NonNull String packageName,
- @UidState int uidState) {
+ @UidState int uidState, @OpFlags int flags) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
- .increaseRejectCount(op, uid, packageName, uidState, 1);
+ .increaseRejectCount(op, uid, packageName, uidState, flags, 1);
}
}
}
void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
- @UidState int uidState, long increment) {
+ @UidState int uidState, @OpFlags int flags, long increment) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
getUpdatedPendingHistoricalOpsMLocked(System.currentTimeMillis())
- .increaseAccessDuration(op, uid, packageName, uidState, increment);
+ .increaseAccessDuration(op, uid, packageName, uidState, flags, increment);
}
}
}
@@ -593,20 +597,20 @@
private static final String TAG_HISTORY = "history";
private static final String TAG_OPS = "ops";
private static final String TAG_UID = "uid";
- private static final String TAG_PACKAGE = "package";
+ private static final String TAG_PACKAGE = "pkg";
private static final String TAG_OP = "op";
- private static final String TAG_STATE = "state";
+ private static final String TAG_STATE = "st";
- private static final String ATTR_VERSION = "version";
- private static final String ATTR_NAME = "name";
- private static final String ATTR_ACCESS_COUNT = "accessCount";
- private static final String ATTR_REJECT_COUNT = "rejectCount";
- private static final String ATTR_ACCESS_DURATION = "accessDuration";
- private static final String ATTR_BEGIN_TIME = "beginTime";
- private static final String ATTR_END_TIME = "endTime";
- private static final String ATTR_OVERFLOW = "overflow";
+ private static final String ATTR_VERSION = "ver";
+ private static final String ATTR_NAME = "na";
+ private static final String ATTR_ACCESS_COUNT = "ac";
+ private static final String ATTR_REJECT_COUNT = "rc";
+ private static final String ATTR_ACCESS_DURATION = "du";
+ private static final String ATTR_BEGIN_TIME = "beg";
+ private static final String ATTR_END_TIME = "end";
+ private static final String ATTR_OVERFLOW = "ov";
- private static final int CURRENT_VERSION = 1;
+ private static final int CURRENT_VERSION = 2;
private final long mBaseSnapshotInterval;
private final long mIntervalCompressionMultiplier;
@@ -657,7 +661,8 @@
@Nullable List<HistoricalOps> readHistoryRawDLocked() {
return collectHistoricalOpsBaseDLocked(Process.INVALID_UID /*filterUid*/,
null /*filterPackageName*/, null /*filterOpNames*/,
- 0 /*filterBeginTimeMills*/, Long.MAX_VALUE /*filterEndTimeMills*/);
+ 0 /*filterBeginTimeMills*/, Long.MAX_VALUE /*filterEndTimeMills*/,
+ AppOpsManager.OP_FLAGS_ALL);
}
@Nullable List<HistoricalOps> readHistoryDLocked() {
@@ -697,9 +702,10 @@
private void collectHistoricalOpsDLocked(@NonNull HistoricalOps currentOps,
int filterUid, @NonNull String filterPackageName, @Nullable String[] filterOpNames,
- long filterBeingMillis, long filterEndMillis) {
+ long filterBeingMillis, long filterEndMillis, @OpFlags int filterFlags) {
final List<HistoricalOps> readOps = collectHistoricalOpsBaseDLocked(filterUid,
- filterPackageName, filterOpNames, filterBeingMillis, filterEndMillis);
+ filterPackageName, filterOpNames, filterBeingMillis, filterEndMillis,
+ filterFlags);
if (readOps != null) {
final int readCount = readOps.size();
for (int i = 0; i < readCount; i++) {
@@ -711,7 +717,7 @@
private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsBaseDLocked(
int filterUid, @NonNull String filterPackageName, @Nullable String[] filterOpNames,
- long filterBeginTimeMillis, long filterEndTimeMillis) {
+ long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags) {
File baseDir = null;
try {
baseDir = mHistoricalAppOpsDir.startRead();
@@ -724,8 +730,8 @@
final long[] globalContentOffsetMillis = {0};
final LinkedList<HistoricalOps> ops = collectHistoricalOpsRecursiveDLocked(
baseDir, filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
- filterEndTimeMillis, globalContentOffsetMillis, null /*outOps*/,
- 0 /*depth*/, historyFiles);
+ filterEndTimeMillis, filterFlags, globalContentOffsetMillis,
+ null /*outOps*/, 0 /*depth*/, historyFiles);
if (DEBUG) {
filesInvariant.stopTracking(baseDir);
}
@@ -741,7 +747,8 @@
private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsRecursiveDLocked(
@NonNull File baseDir, int filterUid, @NonNull String filterPackageName,
@Nullable String[] filterOpNames, long filterBeginTimeMillis,
- long filterEndTimeMillis, @NonNull long[] globalContentOffsetMillis,
+ long filterEndTimeMillis, @OpFlags int filterFlags,
+ @NonNull long[] globalContentOffsetMillis,
@Nullable LinkedList<HistoricalOps> outOps, int depth,
@NonNull Set<String> historyFiles)
throws IOException, XmlPullParserException {
@@ -757,7 +764,7 @@
final List<HistoricalOps> readOps = readHistoricalOpsLocked(baseDir,
previousIntervalEndMillis, currentIntervalEndMillis, filterUid,
filterPackageName, filterOpNames, filterBeginTimeMillis, filterEndTimeMillis,
- globalContentOffsetMillis, depth, historyFiles);
+ filterFlags, globalContentOffsetMillis, depth, historyFiles);
// Empty is a special signal to stop diving
if (readOps != null && readOps.isEmpty()) {
@@ -767,7 +774,7 @@
// Collect older historical data from subsequent levels
outOps = collectHistoricalOpsRecursiveDLocked(
baseDir, filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
- filterEndTimeMillis, globalContentOffsetMillis, outOps, depth + 1,
+ filterEndTimeMillis, filterFlags, globalContentOffsetMillis, outOps, depth + 1,
historyFiles);
// Make older historical data relative to the current historical level
@@ -836,22 +843,24 @@
previousIntervalEndMillis, currentIntervalEndMillis,
Process.INVALID_UID /*filterUid*/, null /*filterPackageName*/,
null /*filterOpNames*/, Long.MIN_VALUE /*filterBeginTimeMillis*/,
- Long.MAX_VALUE /*filterEndTimeMillis*/, null, depth,
- null /*historyFiles*/);
+ Long.MAX_VALUE /*filterEndTimeMillis*/, AppOpsManager.OP_FLAGS_ALL,
+ null, depth, null /*historyFiles*/);
if (DEBUG) {
enforceOpsWellFormed(existingOps);
}
// Offset existing ops to account for elapsed time
- final int existingOpCount = existingOps.size();
- if (existingOpCount > 0) {
- // Compute elapsed time
- final long elapsedTimeMillis = passedOps.get(passedOps.size() - 1)
+ if (existingOps != null) {
+ final int existingOpCount = existingOps.size();
+ if (existingOpCount > 0) {
+ // Compute elapsed time
+ final long elapsedTimeMillis = passedOps.get(passedOps.size() - 1)
.getEndTimeMillis();
- for (int i = 0; i < existingOpCount; i++) {
- final HistoricalOps existingOp = existingOps.get(i);
- existingOp.offsetBeginAndEndTime(elapsedTimeMillis);
+ for (int i = 0; i < existingOpCount; i++) {
+ final HistoricalOps existingOp = existingOps.get(i);
+ existingOp.offsetBeginAndEndTime(elapsedTimeMillis);
+ }
}
}
@@ -864,9 +873,10 @@
// Consolidate passed ops at the current slot duration ensuring each snapshot is
// full. To achieve this we put all passed and existing ops in a list and will
// merge them to ensure each represents a snapshot at the current granularity.
- final List<HistoricalOps> allOps = new LinkedList<>();
- allOps.addAll(passedOps);
- allOps.addAll(existingOps);
+ final List<HistoricalOps> allOps = new LinkedList<>(passedOps);
+ if (existingOps != null) {
+ allOps.addAll(existingOps);
+ }
if (DEBUG) {
enforceOpsWellFormed(allOps);
@@ -944,10 +954,10 @@
overflowedOps, oldFileNames, depth + 1);
}
- private @NonNull List<HistoricalOps> readHistoricalOpsLocked(File baseDir,
- long intervalBeginMillis, long intervalEndMillis, int filterUid,
- @Nullable String filterPackageName, @Nullable String[] filterOpNames,
- long filterBeginTimeMillis, long filterEndTimeMillis,
+ private @Nullable List<HistoricalOps> readHistoricalOpsLocked(File baseDir,
+ long intervalBeginMillis, long intervalEndMillis,
+ int filterUid, @Nullable String filterPackageName, @Nullable String[] filterOpNames,
+ long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags,
@Nullable long[] cumulativeOverflowMillis, int depth,
@NonNull Set<String> historyFiles)
throws IOException, XmlPullParserException {
@@ -973,12 +983,13 @@
}
}
return readHistoricalOpsLocked(file, filterUid, filterPackageName, filterOpNames,
- filterBeginTimeMillis, filterEndTimeMillis, cumulativeOverflowMillis);
+ filterBeginTimeMillis, filterEndTimeMillis, filterFlags,
+ cumulativeOverflowMillis);
}
private @Nullable List<HistoricalOps> readHistoricalOpsLocked(@NonNull File file,
int filterUid, @Nullable String filterPackageName, @Nullable String[] filterOpNames,
- long filterBeginTimeMillis, long filterEndTimeMillis,
+ long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags,
@Nullable long[] cumulativeOverflowMillis)
throws IOException, XmlPullParserException {
if (DEBUG) {
@@ -989,13 +1000,22 @@
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
XmlUtils.beginDocument(parser, TAG_HISTORY);
+
+ // We haven't released version 1 and have more detailed
+ // accounting - just nuke the current state
+ final int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION);
+ if (CURRENT_VERSION == 2 && version < CURRENT_VERSION) {
+ throw new IllegalStateException("Dropping unsupported history "
+ + "version 1 for file:" + file);
+ }
+
final long overflowMillis = XmlUtils.readLongAttribute(parser, ATTR_OVERFLOW, 0);
final int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_OPS.equals(parser.getName())) {
final HistoricalOps ops = readeHistoricalOpsDLocked(parser,
filterUid, filterPackageName, filterOpNames, filterBeginTimeMillis,
- filterEndTimeMillis, cumulativeOverflowMillis);
+ filterEndTimeMillis, filterFlags, cumulativeOverflowMillis);
if (ops == null) {
continue;
}
@@ -1029,7 +1049,8 @@
private @Nullable HistoricalOps readeHistoricalOpsDLocked(
@NonNull XmlPullParser parser, int filterUid, @Nullable String filterPackageName,
@Nullable String[] filterOpNames, long filterBeginTimeMillis,
- long filterEndTimeMillis, @Nullable long[] cumulativeOverflowMillis)
+ long filterEndTimeMillis, @OpFlags int filterFlags,
+ @Nullable long[] cumulativeOverflowMillis)
throws IOException, XmlPullParserException {
final long beginTimeMillis = XmlUtils.readLongAttribute(parser, ATTR_BEGIN_TIME, 0)
+ (cumulativeOverflowMillis != null ? cumulativeOverflowMillis[0] : 0);
@@ -1045,6 +1066,10 @@
}
final long filteredBeginTimeMillis = Math.max(beginTimeMillis, filterBeginTimeMillis);
final long filteredEndTimeMillis = Math.min(endTimeMillis, filterEndTimeMillis);
+ // // Keep reading as subsequent records may start matching
+ // if (filteredEndTimeMillis - filterBeginTimeMillis <= 0) {
+ // return null;
+ // }
final double filterScale = (double) (filteredEndTimeMillis - filteredBeginTimeMillis)
/ (double) (endTimeMillis - beginTimeMillis);
HistoricalOps ops = null;
@@ -1052,7 +1077,7 @@
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_UID.equals(parser.getName())) {
final HistoricalOps returnedOps = readHistoricalUidOpsDLocked(ops, parser,
- filterUid, filterPackageName, filterOpNames, filterScale);
+ filterUid, filterPackageName, filterOpNames, filterFlags, filterScale);
if (ops == null) {
ops = returnedOps;
}
@@ -1067,7 +1092,8 @@
private @Nullable HistoricalOps readHistoricalUidOpsDLocked(
@Nullable HistoricalOps ops, @NonNull XmlPullParser parser, int filterUid,
@Nullable String filterPackageName, @Nullable String[] filterOpNames,
- double filterScale) throws IOException, XmlPullParserException {
+ @OpFlags int filterFlags, double filterScale)
+ throws IOException, XmlPullParserException {
final int uid = XmlUtils.readIntAttribute(parser, ATTR_NAME);
if (filterUid != Process.INVALID_UID && filterUid != uid) {
XmlUtils.skipCurrentTag(parser);
@@ -1077,7 +1103,8 @@
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_PACKAGE.equals(parser.getName())) {
final HistoricalOps returnedOps = readHistoricalPackageOpsDLocked(ops,
- uid, parser, filterPackageName, filterOpNames, filterScale);
+ uid, parser, filterPackageName, filterOpNames, filterFlags,
+ filterScale);
if (ops == null) {
ops = returnedOps;
}
@@ -1089,7 +1116,8 @@
private @Nullable HistoricalOps readHistoricalPackageOpsDLocked(
@Nullable HistoricalOps ops, int uid, @NonNull XmlPullParser parser,
@Nullable String filterPackageName, @Nullable String[] filterOpNames,
- double filterScale) throws IOException, XmlPullParserException {
+ @OpFlags int filterFlags, double filterScale)
+ throws IOException, XmlPullParserException {
final String packageName = XmlUtils.readStringAttribute(parser, ATTR_NAME);
if (filterPackageName != null && !filterPackageName.equals(packageName)) {
XmlUtils.skipCurrentTag(parser);
@@ -1099,7 +1127,7 @@
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_OP.equals(parser.getName())) {
final HistoricalOps returnedOps = readHistoricalOpDLocked(ops, uid,
- packageName, parser, filterOpNames, filterScale);
+ packageName, parser, filterOpNames, filterFlags, filterScale);
if (ops == null) {
ops = returnedOps;
}
@@ -1110,7 +1138,7 @@
private @Nullable HistoricalOps readHistoricalOpDLocked(@Nullable HistoricalOps ops,
int uid, String packageName, @NonNull XmlPullParser parser,
- @Nullable String[] filterOpNames, double filterScale)
+ @Nullable String[] filterOpNames, @OpFlags int filterFlags, double filterScale)
throws IOException, XmlPullParserException {
final int op = XmlUtils.readIntAttribute(parser, ATTR_NAME);
if (filterOpNames != null && !ArrayUtils.contains(filterOpNames,
@@ -1121,8 +1149,8 @@
final int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_STATE.equals(parser.getName())) {
- final HistoricalOps returnedOps = readUidStateDLocked(ops, uid,
- packageName, op, parser, filterScale);
+ final HistoricalOps returnedOps = readStateDLocked(ops, uid,
+ packageName, op, parser, filterFlags, filterScale);
if (ops == null) {
ops = returnedOps;
}
@@ -1131,10 +1159,15 @@
return ops;
}
- private @Nullable HistoricalOps readUidStateDLocked(@Nullable HistoricalOps ops,
+ private @Nullable HistoricalOps readStateDLocked(@Nullable HistoricalOps ops,
int uid, String packageName, int op, @NonNull XmlPullParser parser,
- double filterScale) throws IOException {
- final int uidState = XmlUtils.readIntAttribute(parser, ATTR_NAME);
+ @OpFlags int filterFlags, double filterScale) throws IOException {
+ final long key = XmlUtils.readLongAttribute(parser, ATTR_NAME);
+ final int flags = AppOpsManager.extractFlagsFromKey(key) & filterFlags;
+ if (flags == 0) {
+ return null;
+ }
+ final int uidState = AppOpsManager.extractUidStateFromKey(key);
long accessCount = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_COUNT, 0);
if (accessCount > 0) {
if (!Double.isNaN(filterScale)) {
@@ -1144,7 +1177,7 @@
if (ops == null) {
ops = new HistoricalOps(0, 0);
}
- ops.increaseAccessCount(op, uid, packageName, uidState, accessCount);
+ ops.increaseAccessCount(op, uid, packageName, uidState, flags, accessCount);
}
long rejectCount = XmlUtils.readLongAttribute(parser, ATTR_REJECT_COUNT, 0);
if (rejectCount > 0) {
@@ -1155,7 +1188,7 @@
if (ops == null) {
ops = new HistoricalOps(0, 0);
}
- ops.increaseRejectCount(op, uid, packageName, uidState, rejectCount);
+ ops.increaseRejectCount(op, uid, packageName, uidState, flags, rejectCount);
}
long accessDuration = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_DURATION, 0);
if (accessDuration > 0) {
@@ -1166,7 +1199,7 @@
if (ops == null) {
ops = new HistoricalOps(0, 0);
}
- ops.increaseAccessDuration(op, uid, packageName, uidState, accessDuration);
+ ops.increaseAccessDuration(op, uid, packageName, uidState, flags, accessDuration);
}
return ops;
}
@@ -1241,24 +1274,34 @@
private void writeHistoricalOpDLocked(@NonNull HistoricalOp op,
@NonNull XmlSerializer serializer) throws IOException {
+ final LongSparseArray keys = op.collectKeys();
+ if (keys == null || keys.size() <= 0) {
+ return;
+ }
serializer.startTag(null, TAG_OP);
serializer.attribute(null, ATTR_NAME, Integer.toString(op.getOpCode()));
- for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
- writeUidStateOnLocked(op, uidState, serializer);
+ final int keyCount = keys.size();
+ for (int i = 0; i < keyCount; i++) {
+ writeStateOnLocked(op, keys.keyAt(i), serializer);
}
serializer.endTag(null, TAG_OP);
}
- private void writeUidStateOnLocked(@NonNull HistoricalOp op, @UidState int uidState,
+ private void writeStateOnLocked(@NonNull HistoricalOp op, long key,
@NonNull XmlSerializer serializer) throws IOException {
- final long accessCount = op.getAccessCount(uidState);
- final long rejectCount = op.getRejectCount(uidState);
- final long accessDuration = op.getAccessDuration(uidState);
- if (accessCount == 0 && rejectCount == 0 && accessDuration == 0) {
+ final int uidState = AppOpsManager.extractUidStateFromKey(key);
+ final int flags = AppOpsManager.extractFlagsFromKey(key);
+
+ final long accessCount = op.getAccessCount(uidState, uidState, flags);
+ final long rejectCount = op.getRejectCount(uidState, uidState, flags);
+ final long accessDuration = op.getAccessDuration(uidState, uidState, flags);
+
+ if (accessCount <= 0 && rejectCount <= 0 && accessDuration <= 0) {
return;
}
+
serializer.startTag(null, TAG_STATE);
- serializer.attribute(null, ATTR_NAME, Integer.toString(uidState));
+ serializer.attribute(null, ATTR_NAME, Long.toString(key));
if (accessCount > 0) {
serializer.attribute(null, ATTR_ACCESS_COUNT, Long.toString(accessCount));
}
@@ -1532,24 +1575,29 @@
mWriter.print(mEntryPrefix);
mWriter.print(AppOpsManager.opToName(ops.getOpCode()));
mWriter.println(":");
- for (int uidState = 0; uidState < AppOpsManager._NUM_UID_STATE; uidState++) {
+ final LongSparseArray keys = ops.collectKeys();
+ final int keyCount = keys.size();
+ for (int i = 0; i < keyCount; i++) {
+ final long key = keys.keyAt(i);
+ final int uidState = AppOpsManager.extractUidStateFromKey(key);
+ final int flags = AppOpsManager.extractFlagsFromKey(key);
boolean printedUidState = false;
- final long accessCount = ops.getAccessCount(uidState);
+ final long accessCount = ops.getAccessCount(uidState, uidState, flags);
if (accessCount > 0) {
if (!printedUidState) {
mWriter.print(mUidStatePrefix);
- mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+ mWriter.print(AppOpsManager.keyToString(key));
mWriter.print(" = ");
printedUidState = true;
}
mWriter.print("access=");
mWriter.print(accessCount);
}
- final long rejectCount = ops.getRejectCount(uidState);
+ final long rejectCount = ops.getRejectCount(uidState, uidState, flags);
if (rejectCount > 0) {
if (!printedUidState) {
mWriter.print(mUidStatePrefix);
- mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+ mWriter.print(AppOpsManager.keyToString(key));
mWriter.print(" = ");
printedUidState = true;
} else {
@@ -1558,11 +1606,11 @@
mWriter.print("reject=");
mWriter.print(rejectCount);
}
- final long accessDuration = ops.getAccessDuration(uidState);
+ final long accessDuration = ops.getAccessDuration(uidState, uidState, flags);
if (accessDuration > 0) {
if (!printedUidState) {
mWriter.print(mUidStatePrefix);
- mWriter.print(AppOpsService.UID_STATE_NAMES[uidState]);
+ mWriter.print(AppOpsManager.keyToString(key));
mWriter.print(" = ");
printedUidState = true;
} else {
diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING
new file mode 100644
index 0000000..f2e2782
--- /dev/null
+++ b/services/core/java/com/android/server/appop/TEST_MAPPING
@@ -0,0 +1,21 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsAppOpsTestCases"
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.appop.AppOpsUpgradeTest"
+ },
+ {
+ "include-filter": "com.android.server.appop.AppOpsServiceTest"
+ },
+ {
+ "include-filter": "com.android.server.appop.AppOpsActiveWatcherTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 9af57da..451fd66 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 @@
}
}
- /*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 @@
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 @@
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 @@
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 37f0496..41a3c98 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 @@
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 @@
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 6bd412b..91d19de 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 @@
@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 @@
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 @@
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 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 58c1882..04073cb 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 @@
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 e9ae516..9882f6c 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 @@
}
/**
- * 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 requestDisplayModesLocked(int colorMode, int modeId) {
+ public void setAllowedDisplayModesLocked(int[] modes) {
+ }
+
+ /**
+ * Sets the requested color mode.
+ */
+ 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 6c00da2..32f34b8 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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
display.dumpLocked(ipw);
}
+ pw.println();
+ mDisplayModeDirector.dump(pw);
+
final int callbackCount = mCallbacks.size();
pw.println();
pw.println("Callbacks: size=" + callbackCount);
@@ -2431,4 +2454,10 @@
}
}
+
+ 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 0000000..af4db07
--- /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 77df10b..5e5ef26 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
mDefaultModeId = activeRecord.mMode.getModeId();
}
+
// Determine whether the active mode is still there.
if (mSupportedModes.indexOfKey(mActiveModeId) < 0) {
if (mActiveModeId != 0) {
@@ -284,6 +294,21 @@
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 @@
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 @@
}
@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 @@
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 @@
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 @@
}
@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 b21f0a7..a7b9051 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 @@
// 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 @@
// 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 @@
}
/**
- * 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 @@
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 2f507d1..60cfbd0 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.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 @@
}
@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 9ab9975..71ec5b0 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 @@
// 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 @@
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 @@
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 47b9c27..1b14ce2 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.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 @@
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 @@
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 @@
RecoverySnapshotListenersStorage listenersStorage,
PlatformKeyManager platformKeyManager,
ApplicationKeyStorage applicationKeyStorage,
- TestOnlyInsecureCertificateHelper TestOnlyInsecureCertificateHelper) {
+ TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper,
+ CleanupManager cleanupManager) {
mContext = context;
mDatabase = recoverableKeyStoreDb;
mRecoverySessionStorage = recoverySessionStorage;
@@ -155,8 +166,10 @@
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 @@
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 0000000..be35b50
--- /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 dffaffe..3f5ac8e 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.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 @@
*
* @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 @@
}
/**
+ * 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 @@
*/
@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 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 @@
*/
@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 @@
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 @@
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 b58ee4b..e79d117 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 @@
/**
* 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 @@
* 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 b0613da..cd5e8cf 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 @@
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 @@
"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 @@
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 @@
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 9e912843..05af13a 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 @@
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 b72e836..a3b72fd 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 @@
}
}
+ 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 3218c86..ff81ad5 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 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 @@
// 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/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index ef77140..a5d291f 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.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 @@
@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 @@
@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 @@
@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 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 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 f26121e..f8c7447 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 @@
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 @@
/**
* 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 @@
* 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/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 19ff438..bb5a221 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -86,6 +86,7 @@
import android.content.res.Configuration;
import android.content.res.ResourceId;
import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -123,6 +124,7 @@
import android.view.animation.TranslateAnimation;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils.Dump;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.AttributeCache;
@@ -558,19 +560,19 @@
}
resId = updateToTranslucentAnimIfNeeded(resId, transit);
if (ResourceId.isValid(resId)) {
- return AnimationUtils.loadAnimation(context, resId);
+ return loadAnimationSafely(context, resId);
}
return null;
}
- Animation loadAnimationRes(LayoutParams lp, int resId) {
+ private Animation loadAnimationRes(LayoutParams lp, int resId) {
Context context = mContext;
if (ResourceId.isValid(resId)) {
AttributeCache.Entry ent = getCachedAnimations(lp);
if (ent != null) {
context = ent.context;
}
- return AnimationUtils.loadAnimation(context, resId);
+ return loadAnimationSafely(context, resId);
}
return null;
}
@@ -579,12 +581,22 @@
if (ResourceId.isValid(resId)) {
AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
if (ent != null) {
- return AnimationUtils.loadAnimation(ent.context, resId);
+ return loadAnimationSafely(ent.context, resId);
}
}
return null;
}
+ @VisibleForTesting
+ Animation loadAnimationSafely(Context context, int resId) {
+ try {
+ return AnimationUtils.loadAnimation(context, resId);
+ } catch (NotFoundException e) {
+ Slog.w(TAG, "Unable to load animation resource", e);
+ return null;
+ }
+ }
+
private int updateToTranslucentAnimIfNeeded(int anim, int transit) {
if (transit == TRANSIT_TRANSLUCENT_ACTIVITY_OPEN && anim == R.anim.activity_open_enter) {
return R.anim.activity_translucent_open_enter;
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index e8882ec..d39f20c 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 @@
SET(ElapsedRealtimeNanos, location.elapsedRealtime.timestampNs);
}
- if (flags & ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS) {
- SET(ElapsedUncertaintyRealtimeNanos, location.elapsedRealtime.timeUncertaintyNs);
- }
-
return object.get();
}
@@ -525,8 +521,7 @@
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 @@
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 @@
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 @@
bearingAccuracyDegrees,
timestamp,
elapsedRealtimeFlags,
- elapsedRealtimeNanos,
- elapsedRealtimeUncertaintyNanos);
+ elapsedRealtimeNanos);
auto result = gnssHal_V2_0->injectBestLocation_2_0(location);
if (!result.isOk() || !result) {
@@ -2821,7 +2813,7 @@
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 f496e81..36251f5 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.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 @@
*/
@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 a19d5d5..eba00812 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1881,19 +1881,6 @@
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/AppStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
index c8e6782..d0158e0 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AppStateTrackerTest.java
@@ -685,10 +685,10 @@
List<OpEntry> entries = new ArrayList<>();
entries.add(new OpEntry(
AppOpsManager.OP_ACCESS_NOTIFICATIONS,
- AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+ AppOpsManager.MODE_IGNORED));
entries.add(new OpEntry(
AppStateTracker.TARGET_OP,
- AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+ AppOpsManager.MODE_IGNORED));
ops.add(new PackageOps(PACKAGE_1, UID_1, entries));
@@ -696,7 +696,7 @@
entries = new ArrayList<>();
entries.add(new OpEntry(
AppStateTracker.TARGET_OP,
- AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+ AppOpsManager.MODE_IGNORED));
ops.add(new PackageOps(PACKAGE_2, UID_2, entries));
@@ -704,7 +704,7 @@
entries = new ArrayList<>();
entries.add(new OpEntry(
AppStateTracker.TARGET_OP,
- AppOpsManager.MODE_ALLOWED, 0, 0, 0, 0, null));
+ AppOpsManager.MODE_ALLOWED));
ops.add(new PackageOps(PACKAGE_1, UID_10_1, entries));
@@ -712,10 +712,10 @@
entries = new ArrayList<>();
entries.add(new OpEntry(
AppStateTracker.TARGET_OP,
- AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+ AppOpsManager.MODE_IGNORED));
entries.add(new OpEntry(
AppOpsManager.OP_ACCESS_NOTIFICATIONS,
- AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
+ AppOpsManager.MODE_IGNORED));
ops.add(new PackageOps(PACKAGE_3, UID_10_3, entries));
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index b13735c..36825af 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.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 @@
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 @@
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 @@
}
).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 @@
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 f19cc5d..4c8b4ba 100755
--- a/services/tests/runtests.py
+++ b/services/tests/runtests.py
@@ -19,7 +19,7 @@
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/appop/AppOpsNotedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
index edd89f9..96f329b 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsNotedWatcherTest.java
@@ -45,21 +45,6 @@
private static final long NOTIFICATION_TIMEOUT_MILLIS = 5000;
- public void testWatchNotedOpsRequiresPermission() {
- // Create a mock listener
- final OnOpNotedListener listener = mock(OnOpNotedListener.class);
-
- // Try to start watching noted ops
- final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
- try {
- appOpsManager.startWatchingNoted(new int[]{AppOpsManager.OP_FINE_LOCATION,
- AppOpsManager.OP_RECORD_AUDIO}, listener);
- fail("Watching noted ops shoudl require " + Manifest.permission.WATCH_APPOPS);
- } catch (SecurityException expected) {
- /*ignored*/
- }
- }
-
@Test
public void testWatchNotedOps() {
// Create a mock listener
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index eb0c627..66d2bab 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -107,8 +107,8 @@
}
final AppOpsService.Op _op1 = ops.get(op1);
final AppOpsService.Op _op2 = ops.get(op2);
- final int mode1 = (_op1 == null) ? defaultModeOp1 : _op1.mode;
- final int mode2 = (_op2 == null) ? defaultModeOp2 : _op2.mode;
+ final int mode1 = (_op1 == null) ? defaultModeOp1 : _op1.getMode();
+ final int mode2 = (_op2 == null) ? defaultModeOp2 : _op2.getMode();
assertEquals(mode1, mode2);
if (mode1 != defaultModeOp1) {
numberOfNonDefaultOps++;
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 c78b96d..5bab65c 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.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 @@
@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 @@
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 0000000..0b15a12
--- /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 35215c3..2658af6 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 @@
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 @@
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 7de9ffc..932a769 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 @@
}
@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 8caa39d..1f86171 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 @@
/** 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 @@
/** 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 @@
/** 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 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 @@
@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 @@
@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 @@
@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 @@
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 @@
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 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 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 @@
@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 @@
/** 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 @@
@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 @@
*/
@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 @@
@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 @@
@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 @@
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 @@
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/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index b91f3ec..6e09167 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -23,29 +23,29 @@
import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
-
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
-import androidx.test.filters.SmallTest;
-
import org.junit.Before;
import org.junit.Test;
+import androidx.test.filters.SmallTest;
+
/**
* Test class for {@link AppTransition}.
*
* Build/Install/Run:
- * atest FrameworksServicesTests:AppTransitionTests
+ * atest WmTests:AppTransitionTests
*/
@SmallTest
@Presubmit
@@ -167,4 +167,11 @@
assertFalse(dc1.mOpeningApps.contains(token1));
}
+ @Test
+ public void testLoadAnimationSafely() {
+ DisplayContent dc = createNewDisplay(Display.STATE_ON);
+ assertNull(dc.mAppTransition.loadAnimationSafely(
+ getInstrumentation().getTargetContext(), -1));
+ }
+
}
diff --git a/services/usage/java/com/android/server/usage/AppTimeLimitController.java b/services/usage/java/com/android/server/usage/AppTimeLimitController.java
index 731cbf4..f3d6387 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 @@
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 @@
* 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 @@
"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 b14d722..27fdbcb 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 @@
@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 @@
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 @@
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 @@
}
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 5ac4a46..4359978 100644
--- a/startop/iorap/tests/Android.bp
+++ b/startop/iorap/tests/Android.bp
@@ -29,7 +29,7 @@
// 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 99f4add..b967e72 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 919154d..bcd1103 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 16dcbe2..b1e6194 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 @@
/**
* @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 @@
// 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 @@
}
}
- private fun testAnyMethod(func : (RequestId) -> Unit) {
+ private fun testAnyMethod(func: (RequestId) -> Unit) {
val taskListener = spy(DummyTaskListener())!!
try {
@@ -68,14 +70,13 @@
// 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 @@
@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 @@
@Test
fun testOnSystemServiceEvent() {
- testAnyMethod { requestId : RequestId ->
+ testAnyMethod { requestId: RequestId ->
iorapService.onSystemServiceEvent(requestId,
SystemServiceEvent(SystemServiceEvent.TYPE_START))
}
@@ -113,9 +114,9 @@
@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 4abbb3e..8fa0cde 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 @@
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 @@
*/
@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 @@
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 @@
@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 @@
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 @@
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 ac60e96..22a3cfa 100644
--- a/startop/view_compiler/dex_builder_test/Android.bp
+++ b/startop/view_compiler/dex_builder_test/Android.bp
@@ -43,7 +43,7 @@
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 6ac5fc5..b335663 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 92e2a71..82509b9 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 42d4161..f7b1674 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 a3b1b6c..3dfb20c 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/telecomm/java/android/telecom/CallIdentification.java b/telecomm/java/android/telecom/CallIdentification.java
index d15e024..745affd 100644
--- a/telecomm/java/android/telecom/CallIdentification.java
+++ b/telecomm/java/android/telecom/CallIdentification.java
@@ -44,7 +44,7 @@
* A {@link CallScreeningService} uses this class to create new instances of
* {@link CallIdentification} for a screened call.
*/
- public static class Builder {
+ public final static class Builder {
private CharSequence mName;
private CharSequence mDescription;
private CharSequence mDetails;
@@ -67,7 +67,7 @@
* @param callIdAppName The app name.
* @hide
*/
- public Builder(String callIdPackageName, CharSequence callIdAppName) {
+ public Builder(@NonNull String callIdPackageName, @NonNull CharSequence callIdAppName) {
mPackageName = callIdPackageName;
mAppName = callIdAppName;
}
@@ -80,7 +80,7 @@
* @param name The name associated with the call, or {@code null} if none is provided.
* @return Builder instance.
*/
- public Builder setName(@Nullable CharSequence name) {
+ public @NonNull Builder setName(@Nullable CharSequence name) {
mName = name;
return this;
}
@@ -97,7 +97,7 @@
* @param description The call description, or {@code null} if none is provided.
* @return Builder instance.
*/
- public Builder setDescription(@Nullable CharSequence description) {
+ public @NonNull Builder setDescription(@Nullable CharSequence description) {
mDescription = description;
return this;
}
@@ -114,7 +114,8 @@
* @param details The call details, or {@code null} if none is provided.
* @return Builder instance.
*/
- public Builder setDetails(@Nullable CharSequence details) {
+
+ public @NonNull Builder setDetails(@Nullable CharSequence details) {
mDetails = details;
return this;
}
@@ -127,7 +128,7 @@
* @param photo The photo associated with the call, or {@code null} if none was provided.
* @return Builder instance.
*/
- public Builder setPhoto(@Nullable Icon photo) {
+ public @NonNull Builder setPhoto(@Nullable Icon photo) {
mPhoto = photo;
return this;
}
@@ -141,7 +142,7 @@
* @param nuisanceConfidence The nuisance confidence.
* @return The builder.
*/
- public Builder setNuisanceConfidence(@NuisanceConfidence int nuisanceConfidence) {
+ public @NonNull Builder setNuisanceConfidence(@NuisanceConfidence int nuisanceConfidence) {
mNuisanceConfidence = nuisanceConfidence;
return this;
}
@@ -152,7 +153,7 @@
*
* @return {@link CallIdentification} instance.
*/
- public CallIdentification build() {
+ public @NonNull CallIdentification build() {
return new CallIdentification(mName, mDescription, mDetails, mPhoto,
mNuisanceConfidence, mPackageName, mAppName);
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index d509168..7688ac6 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -17,6 +17,7 @@
import android.Manifest;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
import android.annotation.SuppressLint;
@@ -814,10 +815,11 @@
* <p>
* The default dialer has access to use this method.
*
- * @return The user outgoing phone account selected by the user.
+ * @return The user outgoing phone account selected by the user, or {@code null} if there is no
+ * user selected outgoing {@link PhoneAccountHandle}.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
+ public @Nullable PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
try {
if (isServiceConnected()) {
return getTelecomService().getUserSelectedOutgoingPhoneAccount(
@@ -833,13 +835,14 @@
* Sets the user-chosen default {@link PhoneAccountHandle} for making outgoing phone calls.
*
* @param accountHandle The {@link PhoneAccountHandle} which will be used by default for making
- * outgoing voice calls.
+ * outgoing voice calls, or {@code null} if no default is specified (the
+ * user will be asked each time a call is placed in this case).
* @hide
*/
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
@TestApi
@SystemApi
- public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
+ public void setUserSelectedOutgoingPhoneAccount(@Nullable PhoneAccountHandle accountHandle) {
try {
if (isServiceConnected()) {
getTelecomService().setUserSelectedOutgoingPhoneAccount(accountHandle);
@@ -1206,7 +1209,8 @@
/**
* Used to set the default dialer package.
*
- * @param packageName to set the default dialer to.
+ * @param packageName to set the default dialer to, or {@code null} if the system provided
+ * dialer should be used instead.
*
* @result {@code true} if the default dialer was successfully changed, {@code false} if
* the specified package does not correspond to an installed dialer, or is already
@@ -1225,7 +1229,7 @@
@RequiresPermission(allOf = {
android.Manifest.permission.MODIFY_PHONE_STATE,
android.Manifest.permission.WRITE_SECURE_SETTINGS})
- public boolean setDefaultDialer(String packageName) {
+ public boolean setDefaultDialer(@Nullable String packageName) {
try {
if (isServiceConnected()) {
return getTelecomService().setDefaultDialer(packageName);
@@ -1239,9 +1243,10 @@
/**
* Determines the package name of the system-provided default phone app.
*
- * @return package name for the system dialer package or null if no system dialer is preloaded.
+ * @return package name for the system dialer package or {@code null} if no system dialer is
+ * preloaded.
*/
- public String getSystemDialerPackage() {
+ public @Nullable String getSystemDialerPackage() {
try {
if (isServiceConnected()) {
return getTelecomService().getSystemDialerPackage();
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 79b7807..9d46300 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -1191,8 +1191,8 @@
* Broadcast Action: A debug code has been entered in the dialer. This intent is
* broadcast by the system and OEM telephony apps may need to receive these broadcasts.
* These "secret codes" are used to activate developer menus by dialing certain codes.
- * And they are of the form {@code *#*#<code>#*#*}. The intent will have the data
- * URI: {@code android_secret_code://<code>}. It is possible that a manifest
+ * And they are of the form {@code *#*#<code>#*#*}. The intent will have the data
+ * URI: {@code android_secret_code://<code>}. It is possible that a manifest
* receiver would be woken up even if it is not currently running.
*
* <p>Requires {@code android.Manifest.permission#CONTROL_INCALL_EXPERIENCE} to
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index 368f0c6..3a34005 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 @@
* @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 @@
/**
* Returns the {@link PreciseCallState} of the call.
*/
+ @NonNull
public PreciseCallState getPreciseCallState() {
return mPreciseCallState;
}
@@ -96,6 +98,7 @@
/**
* 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 47ce632..78623e7 100644
--- a/telephony/java/android/telephony/CarrierRestrictionRules.java
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -177,7 +177,8 @@
* @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 @@
/**
* Builder for a {@link CarrierRestrictionRules}.
*/
- public static class Builder {
+ public static final class Builder {
private final CarrierRestrictionRules mRules;
/** {@hide} */
@@ -341,14 +342,14 @@
}
/** 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 @@
*
* @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 @@
*
* @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 @@
*
* @param carrierRestrictionDefault prioritized carrier list
*/
- public Builder setDefaultCarrierRestriction(
+ public @NonNull Builder setDefaultCarrierRestriction(
@CarrierRestrictionDefault int carrierRestrictionDefault) {
mRules.mCarrierRestrictionDefault = carrierRestrictionDefault;
return this;
@@ -391,7 +394,7 @@
*
* @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 9614dc5..a9d3079 100644
--- a/telephony/java/android/telephony/NetworkRegistrationState.java
+++ b/telephony/java/android/telephony/NetworkRegistrationState.java
@@ -285,6 +285,14 @@
}
/**
+ * @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/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 79c7195..aaf5f33 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1566,6 +1566,7 @@
* 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 @@
*
* @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 @@
* 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 @@
*
* @param slotIndex of which Type Allocation Code is returned
*/
+ @Nullable
public String getManufacturerCode(int slotIndex) {
ITelephony telephony = getITelephony();
if (telephony == null) return null;
@@ -2797,8 +2801,8 @@
* (see {@link #hasCarrierPrivileges}).
* <p>
* These "secret codes" are used to activate developer menus by dialing certain codes.
- * And they are of the form {@code *#*#<code>#*#*}. The intent will have the data
- * URI: {@code android_secret_code://<code>}. It is possible that a manifest
+ * And they are of the form {@code *#*#<code>#*#*}. The intent will have the data
+ * URI: {@code android_secret_code://<code>}. It is possible that a manifest
* receiver would be woken up even if it is not currently running.
* <p>
* It is supposed to replace {@link android.provider.Telephony.Sms.Intents#SECRET_CODE_ACTION}
@@ -6005,6 +6009,7 @@
* @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() {
@@ -10367,12 +10372,6 @@
@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 a4ed775..9d072f0 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -19,7 +19,7 @@
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 @@
* 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 @@
* 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 @@
TYPE_IMS,
TYPE_CBS,
TYPE_IA,
- TYPE_EMERGENCY
+ TYPE_EMERGENCY,
+ TYPE_MCX
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApnType {}
@@ -206,6 +209,7 @@
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 @@
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 @@
* {@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 ad34349..afbf46d 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -17,6 +17,7 @@
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 @@
*
* @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 337375a..a09844d 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 @@
*
* @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 @@
*
* @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 10001bc..464db34 100644
--- a/telephony/java/android/telephony/ims/ImsSsData.java
+++ b/telephony/java/android/telephony/ims/ImsSsData.java
@@ -17,6 +17,7 @@
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 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 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 @@
* 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 @@
* service data.
*/
public @NonNull Builder setCallForwardingInfo(
- @NonNull ImsCallForwardInfo[] imsCallForwardInfos) {
+ @NonNull List<ImsCallForwardInfo> imsCallForwardInfos) {
mImsSsData.mCfInfo = imsCallForwardInfos;
return this;
}
@@ -360,8 +364,8 @@
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 @@
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 @@
/** @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 @@
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 @@
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 @@
* @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 303a9fe..18e7530 100644
--- a/telephony/java/android/telephony/ims/ImsSsInfo.java
+++ b/telephony/java/android/telephony/ims/ImsSsInfo.java
@@ -173,7 +173,7 @@
/**
* 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 @@
/**
* @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 e87d28c..d5061a3 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -141,6 +141,8 @@
/** 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 @@
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 f23a665..e1f56b8 100644
--- a/tests/ActivityManagerPerfTests/tests/Android.mk
+++ b/tests/ActivityManagerPerfTests/tests/Android.mk
@@ -21,7 +21,7 @@
$(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 a1ab33a..04aef47 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 ffb5404..76c40b2 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 58fb136..daff76f 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.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 f7dab03..bc528d4 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 3bf56ce..8e82219 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 e1263db..996c5a5 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.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 f05f323..ba20640 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 @@
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 60c9423..7a7471d 100644
--- a/tests/ActivityManagerPerfTests/utils/Android.mk
+++ b/tests/ActivityManagerPerfTests/utils/Android.mk
@@ -23,7 +23,7 @@
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 67071d2..fc787ba 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 @@
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 1fb548b..f50bca5 100644
--- a/tests/AppLaunch/Android.mk
+++ b/tests/AppLaunch/Android.mk
@@ -12,7 +12,7 @@
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 5ea8ff1..9d7319f 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.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.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 6d08366..332b680 100644
--- a/tests/AppLaunchWear/Android.mk
+++ b/tests/AppLaunchWear/Android.mk
@@ -12,7 +12,7 @@
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 d36d84e..97701c6 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.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.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 b10305d..f47cf96 100644
--- a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk
+++ b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk
@@ -24,7 +24,7 @@
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 afae155..aec9f77 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 9bb1e28..a532422 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 fd20f4a..7d826f7 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 eb8f6c3..fe4dc42 100644
--- a/tests/Camera2Tests/CameraToo/tests/Android.mk
+++ b/tests/Camera2Tests/CameraToo/tests/Android.mk
@@ -20,6 +20,6 @@
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 30210ba..8d35749 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 9c47a26..643f9eb 100644
--- a/tests/Compatibility/Android.mk
+++ b/tests/Compatibility/Android.mk
@@ -17,7 +17,7 @@
# 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 95eb5c9..d683ec7 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.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 b61ec34..960ea49 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 f324eb1..62c1ba8 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/Android.mk
+++ b/tests/DynamicCodeLoggerIntegrationTests/Android.mk
@@ -67,7 +67,7 @@
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 4327da2..08fac30 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 f70b9c8..f8a1ec9 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 4f9aeea..db2f659 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.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 ba63940..5b1a36b 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 6a8dfe8..e438822 100644
--- a/tests/FlickerTests/lib/Android.mk
+++ b/tests/FlickerTests/lib/Android.mk
@@ -24,7 +24,7 @@
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 @@
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 6306f0e..e00a247 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.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.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 f6e8192..0a3fe3c 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 @@
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 0da8761..c54396f 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.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 717d187..3f86f0d 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 @@
/**
* 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 0e3f58d..5be89ba 100644
--- a/tests/FlickerTests/lib/test/Android.mk
+++ b/tests/FlickerTests/lib/test/Android.mk
@@ -25,7 +25,7 @@
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 d30172d..6451a57 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 42b2aca..7d77126 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 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 5a24e6d..c46175c 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 f7fa0d5..dd6fed0 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 @@
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 34f4ebb..b6860cb 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.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 2b62fcf..6590b86 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.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 42b161f..4771b02 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.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 92bb1ea..65888ac 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.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.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 fec248c..61cca0d 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 7061b23..00e11c0 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.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 7e71369..7818c4e 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.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 745569a..63018ec 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 @@
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 de7639d..1aba930 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.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 1bd519c..a81fa8e 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 @@
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 8a15cbd..50dba81 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 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 3eab68d..117ac5a 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 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 40bd4e9..1d30df9 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 @@
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 da56696..2e26ef1 100644
--- a/tests/Internal/Android.mk
+++ b/tests/Internal/Android.mk
@@ -11,7 +11,7 @@
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 e5a5694..c85c3b1 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 6531c93..7b67e9e 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 881f628..65ff6eb 100644
--- a/tests/Internal/src/android/app/WallpaperColorsTest.java
+++ b/tests/Internal/src/android/app/WallpaperColorsTest.java
@@ -20,8 +20,9 @@
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 7f06f2c..476b991 100644
--- a/tests/Internal/src/android/app/WallpaperInfoTest.java
+++ b/tests/Internal/src/android/app/WallpaperInfoTest.java
@@ -26,9 +26,10 @@
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 b9e282e..592aa3a 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.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 39608a4..17fa931 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.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 a7d5ae8..d92cfce 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 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 73df9a0..d0bb8e3 100644
--- a/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java
+++ b/tests/Internal/src/com/android/internal/graphics/ColorUtilsTest.java
@@ -16,13 +16,14 @@
package com.android.internal.graphics;
+import static org.junit.Assert.assertTrue;
+
import android.graphics.Color;
-import android.support.test.filters.SmallTest;
+
+import androidx.test.filters.SmallTest;
import org.junit.Test;
-import static org.junit.Assert.assertTrue;
-
@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 a64f8a6..540a1ec 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.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 1c1c2a4..1e4aacc 100644
--- a/tests/PackageWatchdog/Android.mk
+++ b/tests/PackageWatchdog/Android.mk
@@ -22,7 +22,7 @@
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 fa89528..540edb4 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 77cd62e..598f60a 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -24,7 +24,8 @@
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 7b348d7..a276584 100644
--- a/tests/RcsTests/Android.mk
+++ b/tests/RcsTests/Android.mk
@@ -11,7 +11,7 @@
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 a7e7d47..b1706a0 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 89d32ab..e898942 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 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 726b9cd..356688d 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 @@
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 a109310..572fcb8 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 @@
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 de2688c..038b2e8 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 @@
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 5724054..283c71b 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 @@
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 6361a39..2d95513 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 @@
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 beb4f8a..fb51bda 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 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 db9376b..206f867 100644
--- a/tests/RollbackTest/Android.mk
+++ b/tests/RollbackTest/Android.mk
@@ -107,7 +107,7 @@
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 ac39f85..70cd867 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 e57a768..5380dc9 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 ddcf1da..267ef73 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.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 e10f866..8a925b9 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.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 a6054e8..4780f30 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.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.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;
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 2f989f3..e8cbd60 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,11 @@
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.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -30,13 +35,9 @@
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;
diff --git a/tests/ServiceCrashTest/Android.mk b/tests/ServiceCrashTest/Android.mk
index d1f6450..617ee7c 100644
--- a/tests/ServiceCrashTest/Android.mk
+++ b/tests/ServiceCrashTest/Android.mk
@@ -12,7 +12,7 @@
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 cd29b51..4304fb0 100644
--- a/tests/UsageStatsPerfTests/Android.mk
+++ b/tests/UsageStatsPerfTests/Android.mk
@@ -21,7 +21,7 @@
$(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 596a79c..9891548 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 c9b51dc..b8892eb 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 e2a4c26..7d9d0d5 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.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 0105893..adcd11a 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.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 @@
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 4e215cc..aef993b 100644
--- a/tests/UsbTests/Android.mk
+++ b/tests/UsbTests/Android.mk
@@ -24,7 +24,7 @@
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 5d60695..03d1a3e 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 4affad3..e55bc98 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 ea027d7..89dc79c 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 4b93ca3..ca1eb70 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.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 7800a80..1c2d167 100644
--- a/tests/WindowAnimationJank/Android.mk
+++ b/tests/WindowAnimationJank/Android.mk
@@ -26,7 +26,7 @@
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 1fb502a..6792a8b 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 bf739fa..a8ace162 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 1a0e8fa..fbc1a65 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -939,11 +939,19 @@
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 @@
}
@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/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 6f58893..ee97628 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.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 @@
}
/**
+ * 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 @@
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 50c79da..6305228 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 @@
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,6 +112,95 @@
}
}
+
+ /**
+ * Build a {@link Property} from a getter and an inspectable property annotation.
+ *
+ * @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 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);
+ }
+
+ mAnnotationUtils
+ .typedValueByName("hasAttributeId", Boolean.class, accessor, annotation)
+ .ifPresent(property::setAttributeIdInferrableFromR);
+
+ 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 and fields must be public.",
+ element);
+ }
+
+ if (modifiers.contains(Modifier.ABSTRACT)) {
+ throw new ProcessingException(
+ "Property getter methods must not be abstract.",
+ element);
+ }
+
+ if (modifiers.contains(Modifier.STATIC)) {
+ throw new ProcessingException(
+ "Property getter methods and fields must not be static.",
+ element);
+ }
+ }
+
/**
* Check that an element is shaped like a getter.
*
@@ -127,25 +216,7 @@
}
final ExecutableElement method = (ExecutableElement) element;
- final Set<Modifier> modifiers = method.getModifiers();
- if (modifiers.contains(Modifier.PRIVATE)) {
- throw new ProcessingException(
- "Property getter methods must not be private.",
- element);
- }
-
- if (modifiers.contains(Modifier.ABSTRACT)) {
- throw new ProcessingException(
- "Property getter methods must not be abstract.",
- element);
- }
-
- if (modifiers.contains(Modifier.STATIC)) {
- throw new ProcessingException(
- "Property getter methods must not be static.",
- element);
- }
if (!method.getParameters().isEmpty()) {
throw new ProcessingException(
@@ -171,77 +242,41 @@
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 @@
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 @@
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 @@
flagMapping.ifPresent(value -> {
throw new ProcessingException(
"Cannot use flagMapping and enumMapping simultaneously.",
- getter,
+ accessor,
annotation,
value);
});
@@ -286,12 +321,12 @@
} 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 @@
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 @@
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 @@
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 @@
"%s can only be defined on a method that returns int, got %s.",
typeName,
returnType.toString().toLowerCase()),
- getter,
+ accessor,
annotation);
}
}
@@ -393,21 +449,21 @@
* 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 @@
*
* @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 @@
*
* @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 7b04645..1ab9914 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 @@
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 f6d8bb0..35f0fcf 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.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 @@
@Test
public void testNoAttributeId() {
- final Property property = new Property(
+ final Property property = addProperty(
"noAttributeProperty",
"getNoAttributeProperty",
Property.Type.INT);
@@ -98,19 +100,18 @@
@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 @@
@Test
public void testIntFlag() {
- final Property property = new Property(
+ final Property property = addProperty(
"intFlag",
"getIntFlag",
Property.Type.INT_FLAG);
@@ -139,13 +140,21 @@
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 0000000..a44c43e
--- /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);
+ }
+}