diff options
171 files changed, 3574 insertions, 2141 deletions
diff --git a/Android.bp b/Android.bp index b0e0b35a1f76..6653bd44966b 100644 --- a/Android.bp +++ b/Android.bp @@ -577,25 +577,6 @@ platform_compat_config { src: ":framework-annotation-proc", } -// A library including just UnsupportedAppUsage.java classes. -// -// Provided for target so that libraries can use it without depending on -// the whole of framework or the core platform API. -// -// Built for host so that the annotation processor can also use this annotation. -java_library { - name: "unsupportedappusage-annotation", - host_supported: true, - srcs: [ - "core/java/android/annotation/IntDef.java", - ], - static_libs: [ - "art.module.api.annotations", - ], - - sdk_version: "core_current", -} - // A temporary build target that is conditionally included on the bootclasspath if // android.test.base library has been removed and which provides support for // maintaining backwards compatibility for APKs that target pre-P and depend on @@ -722,6 +703,7 @@ filegroup { srcs: [ "core/java/android/annotation/StringDef.java", "core/java/android/net/annotations/PolicyDirection.java", + "core/java/com/android/internal/util/HexDump.java", "core/java/com/android/internal/util/IState.java", "core/java/com/android/internal/util/State.java", "core/java/com/android/internal/util/StateMachine.java", @@ -970,7 +952,6 @@ filegroup { "core/java/android/content/pm/InstallationFileLocation.aidl", "core/java/android/content/pm/IDataLoaderStatusListener.aidl", "core/java/android/content/pm/IPackageInstallerSessionFileSystemConnector.aidl", - "core/java/android/content/pm/NamedParcelFileDescriptor.aidl", ], path: "core/java", } diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java index 6c48511a12cc..e472d052f32f 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -1353,8 +1353,15 @@ public class BlobStoreManagerService extends SystemService { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "Caller is not allowed to call this; caller=" + Binder.getCallingUid()); - mHandler.post(PooledLambda.obtainRunnable(remoteCallback::sendResult, null) - .recycleOnUse()); + // We post messages back and forth between mHandler thread and mBackgroundHandler + // thread while committing a blob. We need to replicate the same pattern here to + // ensure pending messages have been handled. + mHandler.post(() -> { + mBackgroundHandler.post(() -> { + mHandler.post(PooledLambda.obtainRunnable(remoteCallback::sendResult, null) + .recycleOnUse()); + }); + }); } @Override diff --git a/apex/media/framework/api/current.txt b/apex/media/framework/api/current.txt index 839fb5143196..9cec748e7b8e 100644 --- a/apex/media/framework/api/current.txt +++ b/apex/media/framework/api/current.txt @@ -29,7 +29,7 @@ package android.media { method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException; method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...); method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer); - method @Nullable public String getParserName(); + method @NonNull public String getParserName(); method @NonNull public static java.util.List<java.lang.String> getParserNames(@NonNull android.media.MediaFormat); method public void release(); method public void seek(@NonNull android.media.MediaParser.SeekPoint); @@ -65,6 +65,7 @@ package android.media { field public static final String PARSER_NAME_OGG = "android.media.mediaparser.OggParser"; field public static final String PARSER_NAME_PS = "android.media.mediaparser.PsParser"; field public static final String PARSER_NAME_TS = "android.media.mediaparser.TsParser"; + field public static final String PARSER_NAME_UNKNOWN = "android.media.mediaparser.UNKNOWN"; field public static final String PARSER_NAME_WAV = "android.media.mediaparser.WavParser"; } diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index 5f86ed621084..c0e3d55b45a6 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -452,6 +452,7 @@ public final class MediaParser { @StringDef( prefix = {"PARSER_NAME_"}, value = { + PARSER_NAME_UNKNOWN, PARSER_NAME_MATROSKA, PARSER_NAME_FMP4, PARSER_NAME_MP4, @@ -469,6 +470,7 @@ public final class MediaParser { }) public @interface ParserName {} + public static final String PARSER_NAME_UNKNOWN = "android.media.mediaparser.UNKNOWN"; public static final String PARSER_NAME_MATROSKA = "android.media.mediaparser.MatroskaParser"; public static final String PARSER_NAME_FMP4 = "android.media.mediaparser.FragmentedMp4Parser"; public static final String PARSER_NAME_MP4 = "android.media.mediaparser.Mp4Parser"; @@ -836,14 +838,14 @@ public final class MediaParser { * Returns the name of the backing parser implementation. * * <p>If this instance was creating using {@link #createByName}, the provided name is returned. - * If this instance was created using {@link #create}, this method will return null until the - * first call to {@link #advance}, after which the name of the backing parser implementation is - * returned. + * If this instance was created using {@link #create}, this method will return {@link + * #PARSER_NAME_UNKNOWN} until the first call to {@link #advance}, after which the name of the + * backing parser implementation is returned. * * @return The name of the backing parser implementation, or null if the backing parser * implementation has not yet been selected. */ - @Nullable + @NonNull @ParserName public String getParserName() { return mExtractorName; @@ -880,7 +882,7 @@ public final class MediaParser { // TODO: Apply parameters when creating extractor instances. if (mExtractor == null) { - if (mExtractorName != null) { + if (!mExtractorName.equals(PARSER_NAME_UNKNOWN)) { mExtractor = EXTRACTOR_FACTORIES_BY_NAME.get(mExtractorName).createInstance(); mExtractor.init(new ExtractorOutputAdapter()); } else { @@ -974,9 +976,7 @@ public final class MediaParser { mParserParameters = new HashMap<>(); mOutputConsumer = outputConsumer; mParserNamesPool = parserNamesPool; - if (!sniff) { - mExtractorName = parserNamesPool[0]; - } + mExtractorName = sniff ? PARSER_NAME_UNKNOWN : parserNamesPool[0]; mPositionHolder = new PositionHolder(); mDataSource = new InputReadingDataSource(); removePendingSeek(); diff --git a/apex/permission/framework/Android.bp b/apex/permission/framework/Android.bp index 3fefeb51aa11..793247e88614 100644 --- a/apex/permission/framework/Android.bp +++ b/apex/permission/framework/Android.bp @@ -31,6 +31,10 @@ java_library { "com.android.permission", "test_com.android.permission", ], + permitted_packages: [ + "android.permission", + "android.app.role", + ], hostdex: true, installable: true, visibility: [ diff --git a/api/current.txt b/api/current.txt index ff74ce8b43dc..4925a472fd12 100644 --- a/api/current.txt +++ b/api/current.txt @@ -9,7 +9,6 @@ package android { ctor public Manifest.permission(); field public static final String ACCEPT_HANDOVER = "android.permission.ACCEPT_HANDOVER"; field public static final String ACCESS_BACKGROUND_LOCATION = "android.permission.ACCESS_BACKGROUND_LOCATION"; - field public static final String ACCESS_CALL_AUDIO = "android.permission.ACCESS_CALL_AUDIO"; field public static final String ACCESS_CHECKIN_PROPERTIES = "android.permission.ACCESS_CHECKIN_PROPERTIES"; field public static final String ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION"; field public static final String ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION"; @@ -278,7 +277,7 @@ package android { field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8 field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9 - field public static final int actor = 16844312; // 0x1010618 + field public static final int actor = 16844313; // 0x1010619 field public static final int addPrintersActivity = 16843750; // 0x10103e6 field public static final int addStatesFromChildren = 16842992; // 0x10100f0 field public static final int adjustViewBounds = 16843038; // 0x101011e @@ -328,7 +327,7 @@ package android { field public static final int autoLink = 16842928; // 0x10100b0 field public static final int autoMirrored = 16843754; // 0x10103ea field public static final int autoRemoveFromRecents = 16843847; // 0x1010447 - field public static final int autoRevokePermissions = 16844308; // 0x1010614 + field public static final int autoRevokePermissions = 16844309; // 0x1010615 field public static final int autoSizeMaxTextSize = 16844102; // 0x1010546 field public static final int autoSizeMinTextSize = 16844088; // 0x1010538 field public static final int autoSizePresetSizes = 16844087; // 0x1010537 @@ -710,7 +709,7 @@ package android { field public static final int gravity = 16842927; // 0x10100af field public static final int gridViewStyle = 16842865; // 0x1010071 field public static final int groupIndicator = 16843019; // 0x101010b - field public static final int gwpAsanMode = 16844311; // 0x1010617 + field public static final int gwpAsanMode = 16844312; // 0x1010618 field public static final int hand_hour = 16843011; // 0x1010103 field public static final int hand_minute = 16843012; // 0x1010104 field public static final int handle = 16843354; // 0x101025a @@ -955,7 +954,7 @@ package android { field public static final int mediaRouteButtonStyle = 16843693; // 0x10103ad field public static final int mediaRouteTypes = 16843694; // 0x10103ae field public static final int menuCategory = 16843230; // 0x10101de - field public static final int mimeGroup = 16844310; // 0x1010616 + field public static final int mimeGroup = 16844311; // 0x1010617 field public static final int mimeType = 16842790; // 0x1010026 field public static final int min = 16844089; // 0x1010539 field public static final int minAspectRatio = 16844187; // 0x101059b @@ -1084,7 +1083,7 @@ package android { field public static final int preferenceScreenStyle = 16842891; // 0x101008b field public static final int preferenceStyle = 16842894; // 0x101008e field public static final int presentationTheme = 16843712; // 0x10103c0 - field public static final int preserveLegacyExternalStorage = 16844309; // 0x1010615 + field public static final int preserveLegacyExternalStorage = 16844310; // 0x1010616 field public static final int previewImage = 16843482; // 0x10102da field public static final int primaryContentAlpha = 16844114; // 0x1010552 field public static final int priority = 16842780; // 0x101001c @@ -26401,7 +26400,7 @@ package android.media { method public boolean advance(@NonNull android.media.MediaParser.SeekableInputReader) throws java.io.IOException; method @NonNull public static android.media.MediaParser create(@NonNull android.media.MediaParser.OutputConsumer, @NonNull java.lang.String...); method @NonNull public static android.media.MediaParser createByName(@NonNull String, @NonNull android.media.MediaParser.OutputConsumer); - method @Nullable public String getParserName(); + method @NonNull public String getParserName(); method @NonNull public static java.util.List<java.lang.String> getParserNames(@NonNull android.media.MediaFormat); method public void release(); method public void seek(@NonNull android.media.MediaParser.SeekPoint); @@ -26437,6 +26436,7 @@ package android.media { field public static final String PARSER_NAME_OGG = "android.media.mediaparser.OggParser"; field public static final String PARSER_NAME_PS = "android.media.mediaparser.PsParser"; field public static final String PARSER_NAME_TS = "android.media.mediaparser.TsParser"; + field public static final String PARSER_NAME_UNKNOWN = "android.media.mediaparser.UNKNOWN"; field public static final String PARSER_NAME_WAV = "android.media.mediaparser.WavParser"; } @@ -30348,6 +30348,7 @@ package android.net { method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier(); method public boolean hasCapability(int); method public boolean hasTransport(int); + method public boolean satisfiedBy(@Nullable android.net.NetworkCapabilities); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR; } @@ -37146,11 +37147,10 @@ package android.os { field public static final int EFFECT_TICK = 2; // 0x2 } - public static class VibrationEffect.Composition { - ctor public VibrationEffect.Composition(); - method @Nullable public android.os.VibrationEffect.Composition addPrimitive(int); - method @Nullable public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float); - method @Nullable public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int); + public static final class VibrationEffect.Composition { + method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int); + method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float); + method @NonNull public android.os.VibrationEffect.Composition addPrimitive(int, @FloatRange(from=0.0f, to=1.0f) float, @IntRange(from=0) int); method @NonNull public android.os.VibrationEffect compose(); field public static final int PRIMITIVE_CLICK = 1; // 0x1 field public static final int PRIMITIVE_QUICK_FALL = 6; // 0x6 @@ -37160,8 +37160,8 @@ package android.os { } public abstract class Vibrator { - method @Nullable public Boolean areAllEffectsSupported(@NonNull int...); - method public boolean areAllPrimitivesSupported(@NonNull int...); + method @Nullable public final Boolean areAllEffectsSupported(@NonNull int...); + method public final boolean areAllPrimitivesSupported(@NonNull int...); method @Nullable public boolean[] areEffectsSupported(@NonNull int...); method @NonNull public boolean[] arePrimitivesSupported(@NonNull int...); method @RequiresPermission(android.Manifest.permission.VIBRATE) public abstract void cancel(); @@ -46415,14 +46415,26 @@ package android.telephony { field public static final int BAND_46 = 46; // 0x2e field public static final int BAND_47 = 47; // 0x2f field public static final int BAND_48 = 48; // 0x30 + field public static final int BAND_49 = 49; // 0x31 field public static final int BAND_5 = 5; // 0x5 + field public static final int BAND_50 = 50; // 0x32 + field public static final int BAND_51 = 51; // 0x33 + field public static final int BAND_52 = 52; // 0x34 + field public static final int BAND_53 = 53; // 0x35 field public static final int BAND_6 = 6; // 0x6 field public static final int BAND_65 = 65; // 0x41 field public static final int BAND_66 = 66; // 0x42 field public static final int BAND_68 = 68; // 0x44 field public static final int BAND_7 = 7; // 0x7 field public static final int BAND_70 = 70; // 0x46 + field public static final int BAND_71 = 71; // 0x47 + field public static final int BAND_72 = 72; // 0x48 + field public static final int BAND_73 = 73; // 0x49 + field public static final int BAND_74 = 74; // 0x4a field public static final int BAND_8 = 8; // 0x8 + field public static final int BAND_85 = 85; // 0x55 + field public static final int BAND_87 = 87; // 0x57 + field public static final int BAND_88 = 88; // 0x58 field public static final int BAND_9 = 9; // 0x9 } @@ -46486,7 +46498,13 @@ package android.telephony { field public static final int BAND_83 = 83; // 0x53 field public static final int BAND_84 = 84; // 0x54 field public static final int BAND_86 = 86; // 0x56 + field public static final int BAND_89 = 89; // 0x59 field public static final int BAND_90 = 90; // 0x5a + field public static final int BAND_91 = 91; // 0x5b + field public static final int BAND_92 = 92; // 0x5c + field public static final int BAND_93 = 93; // 0x5d + field public static final int BAND_94 = 94; // 0x5e + field public static final int BAND_95 = 95; // 0x5f } public static final class AccessNetworkConstants.UtranBand { @@ -47774,7 +47792,7 @@ package android.telephony { method public String createAppSpecificSmsToken(android.app.PendingIntent); method @Nullable public String createAppSpecificSmsTokenWithPackageInfo(@Nullable String, @NonNull android.app.PendingIntent); method public java.util.ArrayList<java.lang.String> divideMessage(String); - method @Deprecated public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent); + method public void downloadMultimediaMessage(android.content.Context, String, android.net.Uri, android.os.Bundle, android.app.PendingIntent); method @NonNull public android.os.Bundle getCarrierConfigValues(); method public static android.telephony.SmsManager getDefault(); method public static int getDefaultSmsSubscriptionId(); @@ -47784,7 +47802,7 @@ package android.telephony { method public int getSubscriptionId(); method public void injectSmsPdu(byte[], String, android.app.PendingIntent); method public void sendDataMessage(String, String, short, byte[], android.app.PendingIntent, android.app.PendingIntent); - method @Deprecated public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent); + method public void sendMultimediaMessage(android.content.Context, android.net.Uri, String, android.os.Bundle, android.app.PendingIntent); method public void sendMultipartTextMessage(String, String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>); method public void sendMultipartTextMessage(@NonNull String, @Nullable String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, long); method public void sendMultipartTextMessage(@NonNull String, @Nullable String, @NonNull java.util.List<java.lang.String>, @Nullable java.util.List<android.app.PendingIntent>, @Nullable java.util.List<android.app.PendingIntent>, @NonNull String, @Nullable String); @@ -55749,8 +55767,8 @@ package android.view { } public final class WindowMetrics { - ctor public WindowMetrics(@NonNull android.util.Size, @NonNull android.view.WindowInsets); - method @NonNull public android.util.Size getSize(); + ctor public WindowMetrics(@NonNull android.graphics.Rect, @NonNull android.view.WindowInsets); + method @NonNull public android.graphics.Rect getBounds(); method @NonNull public android.view.WindowInsets getWindowInsets(); } diff --git a/api/system-current.txt b/api/system-current.txt index 7e25382f06d9..6d5ba34fdf9f 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -368,7 +368,6 @@ package android.app { method @RequiresPermission("android.permission.MANAGE_APP_OPS_MODES") public void setUidMode(@NonNull String, int, int); field public static final String OPSTR_ACCEPT_HANDOVER = "android:accept_handover"; field public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility"; - field public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio"; field public static final String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications"; field public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; field public static final String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot"; @@ -2030,10 +2029,10 @@ package android.content.pm { } public static class PackageInstaller.Session implements java.io.Closeable { - method public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]); + method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void addFile(int, @NonNull String, long, @NonNull byte[], @Nullable byte[]); method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void commitTransferred(@NonNull android.content.IntentSender); - method @Nullable public android.content.pm.DataLoaderParams getDataLoaderParams(); - method public void removeFile(int, @NonNull String); + method @Nullable @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public android.content.pm.DataLoaderParams getDataLoaderParams(); + method @RequiresPermission("com.android.permission.USE_INSTALLER_V2") public void removeFile(int, @NonNull String); } public static class PackageInstaller.SessionInfo implements android.os.Parcelable { @@ -2054,7 +2053,7 @@ package android.content.pm { public static class PackageInstaller.SessionParams implements android.os.Parcelable { method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean); method @Deprecated public void setAllowDowngrade(boolean); - method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams); + method @RequiresPermission(allOf={android.Manifest.permission.INSTALL_PACKAGES, "com.android.permission.USE_INSTALLER_V2"}) public void setDataLoaderParams(@NonNull android.content.pm.DataLoaderParams); method public void setDontKillApp(boolean); method public void setEnableRollback(boolean); method public void setEnableRollback(boolean, int); @@ -6211,14 +6210,14 @@ package android.net { method public void onRemoveKeepalivePacketFilter(int); method public void onSaveAcceptUnvalidated(boolean); method public void onSignalStrengthThresholdsUpdated(@NonNull int[]); - method public void onStartSocketKeepalive(int, int, @NonNull android.net.KeepalivePacketData); + method public void onStartSocketKeepalive(int, @IntRange(from=10, to=3600) int, @NonNull android.net.KeepalivePacketData); method public void onStopSocketKeepalive(int); - method public void onValidationStatus(int, @Nullable String); + method public void onValidationStatus(int, @Nullable android.net.Uri); method @NonNull public android.net.Network register(); - method public void sendLinkProperties(@NonNull android.net.LinkProperties); - method public void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities); - method public void sendNetworkScore(int); - method public void sendSocketKeepaliveEvent(int, int); + method public final void sendLinkProperties(@NonNull android.net.LinkProperties); + method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities); + method public final void sendNetworkScore(@IntRange(from=0, to=99) int); + method public final void sendSocketKeepaliveEvent(int, int); method public void setConnected(); method public void unregister(); field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2 @@ -6236,7 +6235,7 @@ package android.net { field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR; } - public static class NetworkAgentConfig.Builder { + public static final class NetworkAgentConfig.Builder { ctor public NetworkAgentConfig.Builder(); method @NonNull public android.net.NetworkAgentConfig build(); method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean); @@ -6304,7 +6303,6 @@ package android.net { public class NetworkRequest implements android.os.Parcelable { method @Nullable public String getRequestorPackageName(); method public int getRequestorUid(); - method public boolean satisfiedBy(@Nullable android.net.NetworkCapabilities); } public static class NetworkRequest.Builder { @@ -8395,12 +8393,12 @@ package android.os { public class RecoverySystem { method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException; - method @RequiresPermission(android.Manifest.permission.RECOVERY) public static boolean clearPrepareForUnattendedUpdate(@NonNull android.content.Context) throws java.io.IOException; + method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void clearPrepareForUnattendedUpdate(@NonNull android.content.Context) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void prepareForUnattendedUpdate(@NonNull android.content.Context, @NonNull String, @Nullable android.content.IntentSender) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException; - method @RequiresPermission(android.Manifest.permission.RECOVERY) public static boolean rebootAndApply(@NonNull android.content.Context, @NonNull String, @NonNull String) throws java.io.IOException; + method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void rebootAndApply(@NonNull android.content.Context, @NonNull String, @NonNull String) throws java.io.IOException; method @RequiresPermission(allOf={android.Manifest.permission.RECOVERY, android.Manifest.permission.REBOOT}) public static void rebootWipeAb(android.content.Context, java.io.File, String) throws java.io.IOException; method @RequiresPermission(android.Manifest.permission.RECOVERY) public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException; method public static boolean verifyPackageCompatibility(java.io.File) throws java.io.IOException; diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index a14c012b2da3..979f950f2770 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -2753,21 +2753,32 @@ message PhoneStateChanged { message BackGesture { enum BackType { - DEFAULT_BACK_TYPE = 0; - COMPLETED = 1; - COMPLETED_REJECTED = 2; // successful because coming from rejected area - INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area - INCOMPLETE = 4; + DEFAULT_BACK_TYPE = 0; + COMPLETED = 1; + COMPLETED_REJECTED = 2; // successful because coming from rejected area + INCOMPLETE_EXCLUDED = 3; // would have been successful but in the exclusion area + INCOMPLETE = 4; // Unsuccessful, for reasons other than below. + INCOMPLETE_FAR_FROM_EDGE = 5; // Unsuccessful, far from the edge. + INCOMPLETE_MULTI_TOUCH = 6; // Unsuccessful, multi touch. + INCOMPLETE_LONG_PRESS = 7; // Unsuccessful, long press. + INCOMPLETE_VERTICAL_MOVE = 8; // Unsuccessful, move vertically. } optional BackType type = 1; - optional int32 y_coordinate = 2; // y coordinate for ACTION_DOWN event + optional int32 y_coordinate = 2 [deprecated = true]; // y coordinate for ACTION_DOWN event + optional int32 start_x = 4; // X coordinate for ACTION_DOWN event. + optional int32 start_y = 5; // Y coordinate for ACTION_DOWN event. + optional int32 end_x = 6; // X coordinate for ACTION_MOVE event. + optional int32 end_y = 7; // Y coordinate for ACTION_MOVE event. + optional int32 left_boundary = 8; // left edge width + left inset + optional int32 right_boundary = 9; // screen width - (right edge width + right inset) + enum WindowHorizontalLocation { DEFAULT_LOCATION = 0; LEFT = 1; RIGHT = 2; } - optional WindowHorizontalLocation x_location = 3; + optional WindowHorizontalLocation x_location = 3 [deprecated = true]; } message ExclusionRectStateChanged { diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp index 0f39efd51b58..e58bbb7893d7 100644 --- a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp @@ -13,14 +13,17 @@ // limitations under the License. #include "src/metrics/EventMetricProducer.h" -#include "metrics_test_helper.h" -#include "tests/statsd_test_util.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <stdio.h> + #include <vector> +#include "metrics_test_helper.h" +#include "stats_event.h" +#include "tests/statsd_test_util.h" + using namespace testing; using android::sp; using std::set; @@ -35,6 +38,22 @@ namespace statsd { const ConfigKey kConfigKey(0, 12345); +namespace { +void makeLogEvent(LogEvent* logEvent, int32_t atomId, int64_t timestampNs, string str) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, atomId); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeString(statsEvent, str.c_str()); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); +} +} // anonymous namespace + TEST(EventMetricProducerTest, TestNoCondition) { int64_t bucketStartTimeNs = 10000000000; int64_t eventStartTimeNs = bucketStartTimeNs + 1; @@ -43,8 +62,11 @@ TEST(EventMetricProducerTest, TestNoCondition) { EventMetric metric; metric.set_id(1); - LogEvent event1(1 /*tag id*/, bucketStartTimeNs + 1); - LogEvent event2(1 /*tag id*/, bucketStartTimeNs + 2); + LogEvent event1(/*uid=*/0, /*pid=*/0); + CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1); + + LogEvent event2(/*uid=*/0, /*pid=*/0); + CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 2); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); @@ -54,8 +76,17 @@ TEST(EventMetricProducerTest, TestNoCondition) { eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1); eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2); - // TODO(b/110561136): get the report and check the content after the ProtoOutputStream change - // is done eventProducer.onDumpReport(); + // Check dump report content. + ProtoOutputStream output; + std::set<string> strSet; + eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/, + true /*erase data*/, FAST, &strSet, &output); + + StatsLogReport report = outputStreamToProto(&output); + EXPECT_TRUE(report.has_event_metrics()); + EXPECT_EQ(2, report.event_metrics().data_size()); + EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos()); + EXPECT_EQ(bucketStartTimeNs + 2, report.event_metrics().data(1).elapsed_timestamp_nanos()); } TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) { @@ -67,8 +98,11 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) { metric.set_id(1); metric.set_condition(StringToId("SCREEN_ON")); - LogEvent event1(1, bucketStartTimeNs + 1); - LogEvent event2(1, bucketStartTimeNs + 10); + LogEvent event1(/*uid=*/0, /*pid=*/0); + CreateNoValuesLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1); + + LogEvent event2(/*uid=*/0, /*pid=*/0); + CreateNoValuesLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10); sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); @@ -81,51 +115,67 @@ TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) { eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2); - // TODO: get the report and check the content after the ProtoOutputStream change is done. - // eventProducer.onDumpReport(); + // Check dump report content. + ProtoOutputStream output; + std::set<string> strSet; + eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/, + true /*erase data*/, FAST, &strSet, &output); + + StatsLogReport report = outputStreamToProto(&output); + EXPECT_TRUE(report.has_event_metrics()); + EXPECT_EQ(1, report.event_metrics().data_size()); + EXPECT_EQ(bucketStartTimeNs + 1, report.event_metrics().data(0).elapsed_timestamp_nanos()); } -// TODO(b/149590301): Update this test to use new socket schema. -//TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) { -// int64_t bucketStartTimeNs = 10000000000; -// int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; -// -// int tagId = 1; -// int conditionTagId = 2; -// -// EventMetric metric; -// metric.set_id(1); -// metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON")); -// MetricConditionLink* link = metric.add_links(); -// link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID")); -// buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what()); -// buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition()); -// -// LogEvent event1(tagId, bucketStartTimeNs + 1); -// EXPECT_TRUE(event1.write("111")); -// event1.init(); -// ConditionKey key1; -// key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "111")}; -// -// LogEvent event2(tagId, bucketStartTimeNs + 10); -// EXPECT_TRUE(event2.write("222")); -// event2.init(); -// ConditionKey key2; -// key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {getMockedDimensionKey(conditionTagId, 2, "222")}; -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse)); -// -// EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue)); -// -// EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs); -// -// eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1); -// eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2); -// -// // TODO: get the report and check the content after the ProtoOutputStream change is done. -// // eventProducer.onDumpReport(); -//} +TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) { + int64_t bucketStartTimeNs = 10000000000; + int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL; + + int tagId = 1; + int conditionTagId = 2; + + EventMetric metric; + metric.set_id(1); + metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON")); + MetricConditionLink* link = metric.add_links(); + link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID")); + buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what()); + buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition()); + + LogEvent event1(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event1, 1 /*tagId*/, bucketStartTimeNs + 1, "111"); + ConditionKey key1; + key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = { + getMockedDimensionKey(conditionTagId, 2, "111")}; + + LogEvent event2(/*uid=*/0, /*pid=*/0); + makeLogEvent(&event2, 1 /*tagId*/, bucketStartTimeNs + 10, "222"); + ConditionKey key2; + key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = { + getMockedDimensionKey(conditionTagId, 2, "222")}; + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + // Condition is false for first event. + EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse)); + // Condition is true for second event. + EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue)); + + EventMetricProducer eventProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs); + + eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1); + eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2); + + // Check dump report content. + ProtoOutputStream output; + std::set<string> strSet; + eventProducer.onDumpReport(bucketStartTimeNs + 20, true /*include current partial bucket*/, + true /*erase data*/, FAST, &strSet, &output); + + StatsLogReport report = outputStreamToProto(&output); + EXPECT_TRUE(report.has_event_metrics()); + EXPECT_EQ(1, report.event_metrics().data_size()); + EXPECT_EQ(bucketStartTimeNs + 10, report.event_metrics().data(0).elapsed_timestamp_nanos()); +} } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index 609324e91daa..d372ffd7e689 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -26,6 +26,7 @@ #include "src/matchers/SimpleLogMatchingTracker.h" #include "src/metrics/MetricProducer.h" #include "src/stats_log_util.h" +#include "stats_event.h" #include "tests/statsd_test_util.h" using namespace testing; @@ -53,6 +54,28 @@ const int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs; const int64_t bucket4StartTimeNs = bucketStartTimeNs + 3 * bucketSizeNs; const int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; +namespace { +shared_ptr<LogEvent> makeLogEvent(int32_t atomId, int64_t timestampNs, int32_t value1, string str1, + int32_t value2) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, atomId); + AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); + + AStatsEvent_writeInt32(statsEvent, value1); + AStatsEvent_writeString(statsEvent, str1.c_str()); + AStatsEvent_writeInt32(statsEvent, value2); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + shared_ptr<LogEvent> logEvent = std::make_shared<LogEvent>(/*uid=*/0, /*pid=*/0); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); + + return logEvent; +} +} // anonymous namespace + /* * Tests that the first bucket works correctly */ @@ -88,769 +111,685 @@ TEST(GaugeMetricProducerTest, TestFirstBucket) { EXPECT_EQ(660000000005, gaugeProducer.getCurrentBucketEndTimeNs()); } -// TODO(b/149590301): Update these tests to use new socket schema. -//TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) { -// GaugeMetric metric; -// metric.set_id(metricId); -// metric.set_bucket(ONE_MINUTE); -// metric.mutable_gauge_fields_filter()->set_include_all(false); -// metric.set_max_pull_delay_sec(INT_MAX); -// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); -// gaugeFieldMatcher->set_field(tagId); -// gaugeFieldMatcher->add_child()->set_field(1); -// gaugeFieldMatcher->add_child()->set_field(3); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); -// event->write(3); -// event->write("some value"); -// event->write(11); -// event->init(); -// data->push_back(event); -// return true; -// })); -// -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// logEventMatcherIndex, eventMatcherWizard, -// tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs, -// pullerManager); -// -// vector<shared_ptr<LogEvent>> allData; -// allData.clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); -// event->write(10); -// event->write("some value"); -// event->write(11); -// event->init(); -// allData.push_back(event); -// -// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin(); -// EXPECT_EQ(INT, it->mValue.getType()); -// EXPECT_EQ(10, it->mValue.int_value); -// it++; -// EXPECT_EQ(11, it->mValue.int_value); -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); -// EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms -// .front().mFields->begin()->mValue.int_value); -// -// allData.clear(); -// std::shared_ptr<LogEvent> event2 = std::make_shared<LogEvent>(tagId, bucket3StartTimeNs + 10); -// event2->write(24); -// event2->write("some value"); -// event2->write(25); -// event2->init(); -// allData.push_back(event2); -// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin(); -// EXPECT_EQ(INT, it->mValue.getType()); -// EXPECT_EQ(24, it->mValue.int_value); -// it++; -// EXPECT_EQ(INT, it->mValue.getType()); -// EXPECT_EQ(25, it->mValue.int_value); -// // One dimension. -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); -// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size()); -// it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin(); -// EXPECT_EQ(INT, it->mValue.getType()); -// EXPECT_EQ(10L, it->mValue.int_value); -// it++; -// EXPECT_EQ(INT, it->mValue.getType()); -// EXPECT_EQ(11L, it->mValue.int_value); -// -// gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs); -// EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size()); -// // One dimension. -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); -// EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size()); -// it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin(); -// EXPECT_EQ(INT, it->mValue.getType()); -// EXPECT_EQ(24L, it->mValue.int_value); -// it++; -// EXPECT_EQ(INT, it->mValue.getType()); -// EXPECT_EQ(25L, it->mValue.int_value); -//} -// -//TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) { -// sp<AlarmMonitor> alarmMonitor; -// GaugeMetric metric; -// metric.set_id(metricId); -// metric.set_bucket(ONE_MINUTE); -// metric.mutable_gauge_fields_filter()->set_include_all(true); -// -// Alert alert; -// alert.set_id(101); -// alert.set_metric_id(metricId); -// alert.set_trigger_if_sum_gt(25); -// alert.set_num_buckets(100); -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// logEventMatcherIndex, eventMatcherWizard, -// -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs, -// bucketStartTimeNs, pullerManager); -// -// sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor); -// EXPECT_TRUE(anomalyTracker != nullptr); -// -// shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); -// event1->write(1); -// event1->write(10); -// event1->init(); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event1); -// EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY)); -// -// gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY)); -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum); -// EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs); -// // Partial buckets are not sent to anomaly tracker. -// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); -// -// // Create an event in the same partial bucket. -// shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 59 * NS_PER_SEC); -// event2->write(1); -// event2->write(10); -// event2->init(); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event2); -// EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum); -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs); -// // Partial buckets are not sent to anomaly tracker. -// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); -// -// // Next event should trigger creation of new bucket and send previous full bucket to anomaly -// // tracker. -// shared_ptr<LogEvent> event3 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 65 * NS_PER_SEC); -// event3->write(1); -// event3->write(10); -// event3->init(); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event3); -// EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum); -// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs); -// EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); -// -// // Next event should trigger creation of new bucket. -// shared_ptr<LogEvent> event4 = -// make_shared<LogEvent>(tagId, bucketStartTimeNs + 125 * NS_PER_SEC); -// event4->write(1); -// event4->write(10); -// event4->init(); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, *event4); -// EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum); -// EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); -//} -// -//TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) { -// GaugeMetric metric; -// metric.set_id(metricId); -// metric.set_bucket(ONE_MINUTE); -// metric.set_max_pull_delay_sec(INT_MAX); -// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); -// gaugeFieldMatcher->set_field(tagId); -// gaugeFieldMatcher->add_child()->set_field(2); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = -// new EventMatcherWizard({new SimpleLogMatchingTracker( -// atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Return(false)) -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, eventUpgradeTimeNs); -// event->write("some value"); -// event->write(2); -// event->init(); -// data->push_back(event); -// return true; -// })); -// -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId, -// bucketStartTimeNs, bucketStartTimeNs, pullerManager); -// -// vector<shared_ptr<LogEvent>> allData; -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1); -// event->write("some value"); -// event->write(1); -// event->init(); -// allData.push_back(event); -// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -// -// gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum); -// EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -// -// allData.clear(); -// event = make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 1); -// event->write("some value"); -// event->write(3); -// event->init(); -// allData.push_back(event); -// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs); -// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -//} -// -//TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) { -// GaugeMetric metric; -// metric.set_id(metricId); -// metric.set_bucket(ONE_MINUTE); -// metric.set_max_pull_delay_sec(INT_MAX); -// metric.set_split_bucket_for_app_upgrade(false); -// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); -// gaugeFieldMatcher->set_field(tagId); -// gaugeFieldMatcher->add_child()->set_field(2); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false)); -// -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// logEventMatcherIndex, eventMatcherWizard, -// tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs, -// pullerManager); -// -// vector<shared_ptr<LogEvent>> allData; -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1); -// event->write("some value"); -// event->write(1); -// event->init(); -// allData.push_back(event); -// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -// -// gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); -// EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); -// EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum); -// EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -//} -// -//TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) { -// GaugeMetric metric; -// metric.set_id(metricId); -// metric.set_bucket(ONE_MINUTE); -// metric.set_max_pull_delay_sec(INT_MAX); -// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); -// gaugeFieldMatcher->set_field(tagId); -// gaugeFieldMatcher->add_child()->set_field(2); -// metric.set_condition(StringToId("SCREEN_ON")); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); -// event->write("some value"); -// event->write(100); -// event->init(); -// data->push_back(event); -// return true; -// })); -// -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, -// logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId, -// bucketStartTimeNs, bucketStartTimeNs, pullerManager); -// -// gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -// EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size()); -// -// vector<shared_ptr<LogEvent>> allData; -// allData.clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); -// event->write("some value"); -// event->write(110); -// event->init(); -// allData.push_back(event); -// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); -// -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); -// EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin() -// ->second.back() -// .mGaugeAtoms.front() -// .mFields->begin() -// ->mValue.int_value); -// -// gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10); -// gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10); -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); -// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size()); -// EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin() -// ->second.back() -// .mGaugeAtoms.front() -// .mFields->begin() -// ->mValue.int_value); -//} -// -//TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) { -// const int conditionTag = 65; -// GaugeMetric metric; -// metric.set_id(1111111); -// metric.set_bucket(ONE_MINUTE); -// metric.mutable_gauge_fields_filter()->set_include_all(true); -// metric.set_condition(StringToId("APP_DIED")); -// metric.set_max_pull_delay_sec(INT_MAX); -// auto dim = metric.mutable_dimensions_in_what(); -// dim->set_field(tagId); -// dim->add_child()->set_field(1); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// EXPECT_CALL(*wizard, query(_, _, _)) -// .WillRepeatedly( -// Invoke([](const int conditionIndex, const ConditionKey& conditionParameters, -// const bool isPartialLink) { -// int pos[] = {1, 0, 0}; -// Field f(conditionTag, pos, 0); -// HashableDimensionKey key; -// key.mutableValues()->emplace_back(f, Value((int32_t)1000000)); -// -// return ConditionState::kTrue; -// })); -// -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); -// event->write(1000); -// event->write(100); -// event->init(); -// data->push_back(event); -// return true; -// })); -// -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, -// logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId, -// bucketStartTimeNs, bucketStartTimeNs, pullerManager); -// -// gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8); -// -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first; -// EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size()); -// EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value); -// -// EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size()); -// -// vector<shared_ptr<LogEvent>> allData; -// allData.clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1); -// event->write(1000); -// event->write(110); -// event->init(); -// allData.push_back(event); -// gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); -// -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); -//} -// -//TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) { -// sp<AlarmMonitor> alarmMonitor; -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false)); -// -// GaugeMetric metric; -// metric.set_id(metricId); -// metric.set_bucket(ONE_MINUTE); -// metric.set_max_pull_delay_sec(INT_MAX); -// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); -// gaugeFieldMatcher->set_field(tagId); -// gaugeFieldMatcher->add_child()->set_field(2); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// logEventMatcherIndex, eventMatcherWizard, -// tagId, -1, tagId, bucketStartTimeNs, bucketStartTimeNs, -// pullerManager); -// -// Alert alert; -// alert.set_id(101); -// alert.set_metric_id(metricId); -// alert.set_trigger_if_sum_gt(25); -// alert.set_num_buckets(2); -// const int32_t refPeriodSec = 60; -// alert.set_refractory_period_secs(refPeriodSec); -// sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor); -// -// int tagId = 1; -// std::shared_ptr<LogEvent> event1 = std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 1); -// event1->write("some value"); -// event1->write(13); -// event1->init(); -// -// gaugeProducer.onDataPulled({event1}, /** succeed */ true, bucketStartTimeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U); -// -// std::shared_ptr<LogEvent> event2 = -// std::make_shared<LogEvent>(tagId, bucketStartTimeNs + bucketSizeNs + 20); -// event2->write("some value"); -// event2->write(15); -// event2->init(); -// -// gaugeProducer.onDataPulled({event2}, /** succeed */ true, bucketStartTimeNs + bucketSizeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), -// std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec); -// -// std::shared_ptr<LogEvent> event3 = -// std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10); -// event3->write("some value"); -// event3->write(26); -// event3->init(); -// -// gaugeProducer.onDataPulled({event3}, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin() -// ->second.front() -// .mFields->begin() -// ->mValue.int_value); -// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), -// std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); -// -// // The event4 does not have the gauge field. Thus the current bucket value is 0. -// std::shared_ptr<LogEvent> event4 = -// std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10); -// event4->write("some value"); -// event4->init(); -// gaugeProducer.onDataPulled({event4}, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty()); -//} -// -//TEST(GaugeMetricProducerTest, TestPullOnTrigger) { -// GaugeMetric metric; -// metric.set_id(metricId); -// metric.set_bucket(ONE_MINUTE); -// metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES); -// metric.mutable_gauge_fields_filter()->set_include_all(false); -// metric.set_max_pull_delay_sec(INT_MAX); -// auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); -// gaugeFieldMatcher->set_field(tagId); -// gaugeFieldMatcher->add_child()->set_field(1); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); -// event->write(4); -// event->init(); -// data->push_back(event); -// return true; -// })) -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20); -// event->write(5); -// event->init(); -// data->push_back(event); -// return true; -// })) -// .WillOnce(Return(true)); -// -// int triggerId = 5; -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// logEventMatcherIndex, eventMatcherWizard, -// tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs, -// pullerManager); -// -// vector<shared_ptr<LogEvent>> allData; -// -// EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size()); -// LogEvent trigger(triggerId, bucketStartTimeNs + 10); -// trigger.init(); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size()); -// trigger.setElapsedTimestampNs(bucketStartTimeNs + 20); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger); -// EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size()); -// trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger); -// -// EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); -// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size()); -// EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin() -// ->second.back() -// .mGaugeAtoms[0] -// .mFields->begin() -// ->mValue.int_value); -// EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin() -// ->second.back() -// .mGaugeAtoms[1] -// .mFields->begin() -// ->mValue.int_value); -//} -// -//TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) { -// GaugeMetric metric; -// metric.set_id(metricId); -// metric.set_bucket(ONE_MINUTE); -// metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES); -// metric.mutable_gauge_fields_filter()->set_include_all(true); -// metric.set_max_pull_delay_sec(INT_MAX); -// auto dimensionMatcher = metric.mutable_dimensions_in_what(); -// // use field 1 as dimension. -// dimensionMatcher->set_field(tagId); -// dimensionMatcher->add_child()->set_field(1); -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 3); -// event->write(3); -// event->write(4); -// event->init(); -// data->push_back(event); -// return true; -// })) -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10); -// event->write(4); -// event->write(5); -// event->init(); -// data->push_back(event); -// return true; -// })) -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 20); -// event->write(4); -// event->write(6); -// event->init(); -// data->push_back(event); -// return true; -// })) -// .WillOnce(Return(true)); -// -// int triggerId = 5; -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// logEventMatcherIndex, eventMatcherWizard, -// tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs, -// pullerManager); -// -// vector<shared_ptr<LogEvent>> allData; -// -// LogEvent trigger(triggerId, bucketStartTimeNs + 3); -// trigger.init(); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); -// trigger.setElapsedTimestampNs(bucketStartTimeNs + 10); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger); -// EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size()); -// EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size()); -// trigger.setElapsedTimestampNs(bucketStartTimeNs + 20); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger); -// EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size()); -// trigger.setElapsedTimestampNs(bucket2StartTimeNs + 1); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger); -// -// EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size()); -// auto bucketIt = gaugeProducer.mPastBuckets.begin(); -// EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size()); -// EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value); -// EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value); -// bucketIt++; -// EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size()); -// EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value); -// EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value); -// EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value); -//} -// -///* -// * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size -// * is smaller than the "min_bucket_size_nanos" specified in the metric config. -// */ -//TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) { -// GaugeMetric metric; -// metric.set_id(metricId); -// metric.set_bucket(FIVE_MINUTES); -// metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES); -// metric.set_min_bucket_size_nanos(10000000000); // 10 seconds -// -// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); -// -// UidMap uidMap; -// SimpleAtomMatcher atomMatcher; -// atomMatcher.set_atom_id(tagId); -// sp<EventMatcherWizard> eventMatcherWizard = new EventMatcherWizard({ -// new SimpleLogMatchingTracker(atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); -// -// sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); -// EXPECT_CALL(*pullerManager, Pull(tagId, _)) -// // Bucket start. -// .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { -// data->clear(); -// shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs); -// event->write("field1"); -// event->write(10); -// event->init(); -// data->push_back(event); -// return true; -// })); -// -// int triggerId = 5; -// GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -// logEventMatcherIndex, eventMatcherWizard, -// tagId, triggerId, tagId, bucketStartTimeNs, bucketStartTimeNs, -// pullerManager); -// -// LogEvent trigger(triggerId, bucketStartTimeNs + 3); -// trigger.init(); -// gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, trigger); -// -// // Check dump report. -// ProtoOutputStream output; -// std::set<string> strSet; -// gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */, -// true, FAST /* dump_latency */, &strSet, &output); -// -// StatsLogReport report = outputStreamToProto(&output); -// EXPECT_TRUE(report.has_gauge_metrics()); -// EXPECT_EQ(0, report.gauge_metrics().data_size()); -// EXPECT_EQ(1, report.gauge_metrics().skipped_size()); -// -// EXPECT_EQ(NanoToMillis(bucketStartTimeNs), -// report.gauge_metrics().skipped(0).start_bucket_elapsed_millis()); -// EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), -// report.gauge_metrics().skipped(0).end_bucket_elapsed_millis()); -// EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size()); -// -// auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0); -// EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason()); -// EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis()); -//} +TEST(GaugeMetricProducerTest, TestPulledEventsNoCondition) { + GaugeMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.mutable_gauge_fields_filter()->set_include_all(false); + metric.set_max_pull_delay_sec(INT_MAX); + auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); + gaugeFieldMatcher->set_field(tagId); + gaugeFieldMatcher->add_child()->set_field(1); + gaugeFieldMatcher->add_child()->set_field(3); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(makeLogEvent(tagId, bucketStartTimeNs + 10, 3, "some value", 11)); + return true; + })); + + GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); + + vector<shared_ptr<LogEvent>> allData; + allData.clear(); + allData.push_back(makeLogEvent(tagId, bucket2StartTimeNs + 1, 10, "some value", 11)); + + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin(); + EXPECT_EQ(INT, it->mValue.getType()); + EXPECT_EQ(10, it->mValue.int_value); + it++; + EXPECT_EQ(11, it->mValue.int_value); + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); + EXPECT_EQ(3, gaugeProducer.mPastBuckets.begin() + ->second.back() + .mGaugeAtoms.front() + .mFields->begin() + ->mValue.int_value); + + allData.clear(); + allData.push_back(makeLogEvent(tagId, bucket3StartTimeNs + 10, 24, "some value", 25)); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin(); + EXPECT_EQ(INT, it->mValue.getType()); + EXPECT_EQ(24, it->mValue.int_value); + it++; + EXPECT_EQ(INT, it->mValue.getType()); + EXPECT_EQ(25, it->mValue.int_value); + // One dimension. + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); + EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size()); + it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin(); + EXPECT_EQ(INT, it->mValue.getType()); + EXPECT_EQ(10L, it->mValue.int_value); + it++; + EXPECT_EQ(INT, it->mValue.getType()); + EXPECT_EQ(11L, it->mValue.int_value); + + gaugeProducer.flushIfNeededLocked(bucket4StartTimeNs); + EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size()); + // One dimension. + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); + EXPECT_EQ(3UL, gaugeProducer.mPastBuckets.begin()->second.size()); + it = gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.front().mFields->begin(); + EXPECT_EQ(INT, it->mValue.getType()); + EXPECT_EQ(24L, it->mValue.int_value); + it++; + EXPECT_EQ(INT, it->mValue.getType()); + EXPECT_EQ(25L, it->mValue.int_value); +} + +TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) { + sp<AlarmMonitor> alarmMonitor; + GaugeMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.mutable_gauge_fields_filter()->set_include_all(true); + + Alert alert; + alert.set_id(101); + alert.set_metric_id(metricId); + alert.set_trigger_if_sum_gt(25); + alert.set_num_buckets(100); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + logEventMatcherIndex, eventMatcherWizard, + -1 /* -1 means no pulling */, -1, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager); + + sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor); + EXPECT_TRUE(anomalyTracker != nullptr); + + LogEvent event1(/*uid=*/0, /*pid=*/0); + CreateTwoValueLogEvent(&event1, tagId, bucketStartTimeNs + 10, 1, 10); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event1); + EXPECT_EQ(1UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY)); + + gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + EXPECT_EQ(0UL, (*gaugeProducer.mCurrentSlicedBucket).count(DEFAULT_METRIC_DIMENSION_KEY)); + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum); + EXPECT_EQ(eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs); + // Partial buckets are not sent to anomaly tracker. + EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); + + // Create an event in the same partial bucket. + LogEvent event2(/*uid=*/0, /*pid=*/0); + CreateTwoValueLogEvent(&event2, tagId, bucketStartTimeNs + 59 * NS_PER_SEC, 1, 10); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event2); + EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum); + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs); + // Partial buckets are not sent to anomaly tracker. + EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); + + // Next event should trigger creation of new bucket and send previous full bucket to anomaly + // tracker. + LogEvent event3(/*uid=*/0, /*pid=*/0); + CreateTwoValueLogEvent(&event3, tagId, bucketStartTimeNs + 65 * NS_PER_SEC, 1, 10); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event3); + EXPECT_EQ(1L, gaugeProducer.mCurrentBucketNum); + EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ((int64_t)bucketStartTimeNs + bucketSizeNs, gaugeProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(1, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); + + // Next event should trigger creation of new bucket. + LogEvent event4(/*uid=*/0, /*pid=*/0); + CreateTwoValueLogEvent(&event4, tagId, bucketStartTimeNs + 125 * NS_PER_SEC, 1, 10); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, event4); + EXPECT_EQ(2L, gaugeProducer.mCurrentBucketNum); + EXPECT_EQ(3UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY)); +} + +TEST(GaugeMetricProducerTest, TestPulledWithUpgrade) { + GaugeMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.set_max_pull_delay_sec(INT_MAX); + auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); + gaugeFieldMatcher->set_field(tagId); + gaugeFieldMatcher->add_child()->set_field(2); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Return(false)) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(CreateRepeatedValueLogEvent(tagId, eventUpgradeTimeNs, 2)); + return true; + })); + + GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); + + vector<shared_ptr<LogEvent>> allData; + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1)); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); + + gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum); + EXPECT_EQ((int64_t)eventUpgradeTimeNs, gaugeProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(2, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); + + allData.clear(); + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 1, 3)); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs); + EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); +} + +TEST(GaugeMetricProducerTest, TestPulledWithAppUpgradeDisabled) { + GaugeMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.set_max_pull_delay_sec(INT_MAX); + metric.set_split_bucket_for_app_upgrade(false); + auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); + gaugeFieldMatcher->set_field(tagId); + gaugeFieldMatcher->add_child()->set_field(2); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false)); + + GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); + + vector<shared_ptr<LogEvent>> allData; + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 1)); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); + + gaugeProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1); + EXPECT_EQ(0UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size()); + EXPECT_EQ(0L, gaugeProducer.mCurrentBucketNum); + EXPECT_EQ(bucketStartTimeNs, gaugeProducer.mCurrentBucketStartTimeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); +} + +TEST(GaugeMetricProducerTest, TestPulledEventsWithCondition) { + GaugeMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.set_max_pull_delay_sec(INT_MAX); + auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); + gaugeFieldMatcher->set_field(tagId); + gaugeFieldMatcher->add_child()->set_field(2); + metric.set_condition(StringToId("SCREEN_ON")); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 100)); + return true; + })); + + GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex, + eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager); + + gaugeProducer.onConditionChanged(true, bucketStartTimeNs + 8); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(100, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); + EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size()); + + vector<shared_ptr<LogEvent>> allData; + allData.clear(); + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 110)); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); + EXPECT_EQ(100, gaugeProducer.mPastBuckets.begin() + ->second.back() + .mGaugeAtoms.front() + .mFields->begin() + ->mValue.int_value); + + gaugeProducer.onConditionChanged(false, bucket2StartTimeNs + 10); + gaugeProducer.flushIfNeededLocked(bucket3StartTimeNs + 10); + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); + EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.size()); + EXPECT_EQ(110L, gaugeProducer.mPastBuckets.begin() + ->second.back() + .mGaugeAtoms.front() + .mFields->begin() + ->mValue.int_value); +} + +TEST(GaugeMetricProducerTest, TestPulledEventsWithSlicedCondition) { + const int conditionTag = 65; + GaugeMetric metric; + metric.set_id(1111111); + metric.set_bucket(ONE_MINUTE); + metric.mutable_gauge_fields_filter()->set_include_all(true); + metric.set_condition(StringToId("APP_DIED")); + metric.set_max_pull_delay_sec(INT_MAX); + auto dim = metric.mutable_dimensions_in_what(); + dim->set_field(tagId); + dim->add_child()->set_field(1); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + EXPECT_CALL(*wizard, query(_, _, _)) + .WillRepeatedly( + Invoke([](const int conditionIndex, const ConditionKey& conditionParameters, + const bool isPartialLink) { + int pos[] = {1, 0, 0}; + Field f(conditionTag, pos, 0); + HashableDimensionKey key; + key.mutableValues()->emplace_back(f, Value((int32_t)1000000)); + + return ConditionState::kTrue; + })); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 1000, 100)); + return true; + })); + + GaugeMetricProducer gaugeProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex, + eventMatcherWizard, tagId, -1, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager); + + gaugeProducer.onSlicedConditionMayChange(true, bucketStartTimeNs + 8); + + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + const auto& key = gaugeProducer.mCurrentSlicedBucket->begin()->first; + EXPECT_EQ(1UL, key.getDimensionKeyInWhat().getValues().size()); + EXPECT_EQ(1000, key.getDimensionKeyInWhat().getValues()[0].mValue.int_value); + + EXPECT_EQ(0UL, gaugeProducer.mPastBuckets.size()); + + vector<shared_ptr<LogEvent>> allData; + allData.clear(); + allData.push_back(CreateTwoValueLogEvent(tagId, bucket2StartTimeNs + 1, 1000, 110)); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); +} + +TEST(GaugeMetricProducerTest, TestPulledEventsAnomalyDetection) { + sp<AlarmMonitor> alarmMonitor; + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return()); + EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false)); + + GaugeMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.set_max_pull_delay_sec(INT_MAX); + auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); + gaugeFieldMatcher->set_field(tagId); + gaugeFieldMatcher->add_child()->set_field(2); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + logEventMatcherIndex, eventMatcherWizard, tagId, -1, tagId, + bucketStartTimeNs, bucketStartTimeNs, pullerManager); + + Alert alert; + alert.set_id(101); + alert.set_metric_id(metricId); + alert.set_trigger_if_sum_gt(25); + alert.set_num_buckets(2); + const int32_t refPeriodSec = 60; + alert.set_refractory_period_secs(refPeriodSec); + sp<AnomalyTracker> anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor); + + int tagId = 1; + vector<shared_ptr<LogEvent>> allData; + allData.clear(); + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 1, 13)); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); + EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U); + + std::shared_ptr<LogEvent> event2 = + CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + bucketSizeNs + 20, 15); + + allData.clear(); + allData.push_back(event2); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); + EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), + std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC) + refPeriodSec); + + allData.clear(); + allData.push_back( + CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 10, 26)); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin() + ->second.front() + .mFields->begin() + ->mValue.int_value); + EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), + std::ceil(1.0 * event2->GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec)); + + // This event does not have the gauge field. Thus the current bucket value is 0. + allData.clear(); + allData.push_back(CreateNoValuesLogEvent(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10)); + gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty()); +} + +TEST(GaugeMetricProducerTest, TestPullOnTrigger) { + GaugeMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES); + metric.mutable_gauge_fields_filter()->set_include_all(false); + metric.set_max_pull_delay_sec(INT_MAX); + auto gaugeFieldMatcher = metric.mutable_gauge_fields_filter()->mutable_fields(); + gaugeFieldMatcher->set_field(tagId); + gaugeFieldMatcher->add_child()->set_field(1); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 10, 4)); + return true; + })) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20, 5)); + return true; + })) + .WillOnce(Return(true)); + + int triggerId = 5; + GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + logEventMatcherIndex, eventMatcherWizard, tagId, triggerId, + tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); + + EXPECT_EQ(0UL, gaugeProducer.mCurrentSlicedBucket->size()); + + LogEvent triggerEvent(/*uid=*/0, /*pid=*/0); + CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 10); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size()); + triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent); + EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size()); + triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent); + + EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size()); + EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.begin()->second.back().mGaugeAtoms.size()); + EXPECT_EQ(4, gaugeProducer.mPastBuckets.begin() + ->second.back() + .mGaugeAtoms[0] + .mFields->begin() + ->mValue.int_value); + EXPECT_EQ(5, gaugeProducer.mPastBuckets.begin() + ->second.back() + .mGaugeAtoms[1] + .mFields->begin() + ->mValue.int_value); +} + +TEST(GaugeMetricProducerTest, TestRemoveDimensionInOutput) { + GaugeMetric metric; + metric.set_id(metricId); + metric.set_bucket(ONE_MINUTE); + metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES); + metric.mutable_gauge_fields_filter()->set_include_all(true); + metric.set_max_pull_delay_sec(INT_MAX); + auto dimensionMatcher = metric.mutable_dimensions_in_what(); + // use field 1 as dimension. + dimensionMatcher->set_field(tagId); + dimensionMatcher->add_child()->set_field(1); + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 3, 3, 4)); + return true; + })) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 10, 4, 5)); + return true; + })) + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(CreateTwoValueLogEvent(tagId, bucketStartTimeNs + 20, 4, 6)); + return true; + })) + .WillOnce(Return(true)); + + int triggerId = 5; + GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + logEventMatcherIndex, eventMatcherWizard, tagId, triggerId, + tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); + + LogEvent triggerEvent(/*uid=*/0, /*pid=*/0); + CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size()); + triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 10); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent); + EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->size()); + EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size()); + triggerEvent.setElapsedTimestampNs(bucketStartTimeNs + 20); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent); + EXPECT_EQ(2UL, gaugeProducer.mCurrentSlicedBucket->begin()->second.size()); + triggerEvent.setElapsedTimestampNs(bucket2StartTimeNs + 1); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent); + + EXPECT_EQ(2UL, gaugeProducer.mPastBuckets.size()); + auto bucketIt = gaugeProducer.mPastBuckets.begin(); + EXPECT_EQ(1UL, bucketIt->second.back().mGaugeAtoms.size()); + EXPECT_EQ(3, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value); + EXPECT_EQ(4, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value); + bucketIt++; + EXPECT_EQ(2UL, bucketIt->second.back().mGaugeAtoms.size()); + EXPECT_EQ(4, bucketIt->first.getDimensionKeyInWhat().getValues().begin()->mValue.int_value); + EXPECT_EQ(5, bucketIt->second.back().mGaugeAtoms[0].mFields->begin()->mValue.int_value); + EXPECT_EQ(6, bucketIt->second.back().mGaugeAtoms[1].mFields->begin()->mValue.int_value); +} + +/* + * Test that BUCKET_TOO_SMALL dump reason is logged when a flushed bucket size + * is smaller than the "min_bucket_size_nanos" specified in the metric config. + */ +TEST(GaugeMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) { + GaugeMetric metric; + metric.set_id(metricId); + metric.set_bucket(FIVE_MINUTES); + metric.set_sampling_type(GaugeMetric::FIRST_N_SAMPLES); + metric.set_min_bucket_size_nanos(10000000000); // 10 seconds + + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, Pull(tagId, _)) + // Bucket start. + .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) { + data->clear(); + data->push_back(CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs, 10)); + return true; + })); + + int triggerId = 5; + GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, + logEventMatcherIndex, eventMatcherWizard, tagId, triggerId, + tagId, bucketStartTimeNs, bucketStartTimeNs, pullerManager); + + LogEvent triggerEvent(/*uid=*/0, /*pid=*/0); + CreateNoValuesLogEvent(&triggerEvent, triggerId, bucketStartTimeNs + 3); + gaugeProducer.onMatchedLogEvent(1 /*log matcher index*/, triggerEvent); + + // Check dump report. + ProtoOutputStream output; + std::set<string> strSet; + gaugeProducer.onDumpReport(bucketStartTimeNs + 9000000, true /* include recent buckets */, true, + FAST /* dump_latency */, &strSet, &output); + + StatsLogReport report = outputStreamToProto(&output); + EXPECT_TRUE(report.has_gauge_metrics()); + EXPECT_EQ(0, report.gauge_metrics().data_size()); + EXPECT_EQ(1, report.gauge_metrics().skipped_size()); + + EXPECT_EQ(NanoToMillis(bucketStartTimeNs), + report.gauge_metrics().skipped(0).start_bucket_elapsed_millis()); + EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), + report.gauge_metrics().skipped(0).end_bucket_elapsed_millis()); + EXPECT_EQ(1, report.gauge_metrics().skipped(0).drop_event_size()); + + auto dropEvent = report.gauge_metrics().skipped(0).drop_event(0); + EXPECT_EQ(BucketDropReason::BUCKET_TOO_SMALL, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(bucketStartTimeNs + 9000000), dropEvent.drop_time_millis()); +} } // namespace statsd } // namespace os diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index c7838fcddb53..8c8836b94f56 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -428,7 +428,7 @@ shared_ptr<LogEvent> CreateTwoValueLogEvent(int atomId, int64_t eventTimeNs, int return logEvent; } -// + void CreateTwoValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs, int32_t value1, int32_t value2) { AStatsEvent* statsEvent = AStatsEvent_obtain(); @@ -531,6 +531,18 @@ shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs) { return logEvent; } +void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs) { + AStatsEvent* statsEvent = AStatsEvent_obtain(); + AStatsEvent_setAtomId(statsEvent, atomId); + AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs); + AStatsEvent_build(statsEvent); + + size_t size; + uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size); + logEvent->parseBuffer(buf, size); + AStatsEvent_release(statsEvent); +} + std::unique_ptr<LogEvent> CreateScreenStateChangedEvent( uint64_t timestampNs, const android::view::DisplayStateEnum state) { AStatsEvent* statsEvent = AStatsEvent_obtain(); diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index 05e1572e3aa9..7c017554d511 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -187,6 +187,8 @@ void CreateRepeatedValueLogEvent(LogEvent* logEvent, int atomId, int64_t eventTi std::shared_ptr<LogEvent> CreateNoValuesLogEvent(int atomId, int64_t eventTimeNs); +void CreateNoValuesLogEvent(LogEvent* logEvent, int atomId, int64_t eventTimeNs); + // Create log event for screen state changed. std::unique_ptr<LogEvent> CreateScreenStateChangedEvent( uint64_t timestampNs, const android::view::DisplayStateEnum state); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index d4749bd8f330..a5dcefcf3ab7 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1088,8 +1088,9 @@ public class AppOpsManager { public static final int OP_ACTIVATE_PLATFORM_VPN = AppProtoEnums.APP_OP_ACTIVATE_PLATFORM_VPN; /** @hide */ public static final int OP_LOADER_USAGE_STATS = AppProtoEnums.APP_OP_LOADER_USAGE_STATS; - /** @hide Access telephony call audio */ - public static final int OP_ACCESS_CALL_AUDIO = AppProtoEnums.APP_OP_ACCESS_CALL_AUDIO; + + // App op deprecated/removed. + private static final int OP_DEPRECATED_1 = AppProtoEnums.APP_OP_DEPRECATED_1; /** @hide Auto-revoke app permissions if app is unused for an extended period */ public static final int OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = @@ -1396,9 +1397,6 @@ public class AppOpsManager { @SystemApi public static final String OPSTR_MANAGE_EXTERNAL_STORAGE = "android:manage_external_storage"; - /** @hide Access telephony call audio */ - @SystemApi - public static final String OPSTR_ACCESS_CALL_AUDIO = "android:access_call_audio"; /** @hide Auto-revoke app permissions if app is unused for an extended period */ @SystemApi @@ -1498,7 +1496,6 @@ public class AppOpsManager { OP_MANAGE_EXTERNAL_STORAGE, OP_INTERACT_ACROSS_PROFILES, OP_LOADER_USAGE_STATS, - OP_ACCESS_CALL_AUDIO, OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, OP_AUTO_REVOKE_MANAGED_BY_INSTALLER, }; @@ -1608,7 +1605,7 @@ public class AppOpsManager { OP_INTERACT_ACROSS_PROFILES, //INTERACT_ACROSS_PROFILES OP_ACTIVATE_PLATFORM_VPN, // ACTIVATE_PLATFORM_VPN OP_LOADER_USAGE_STATS, // LOADER_USAGE_STATS - OP_ACCESS_CALL_AUDIO, // ACCESS_CALL_AUDIO + OP_DEPRECATED_1, // deprecated OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, //AUTO_REVOKE_PERMISSIONS_IF_UNUSED OP_AUTO_REVOKE_MANAGED_BY_INSTALLER, //OP_AUTO_REVOKE_MANAGED_BY_INSTALLER }; @@ -1713,7 +1710,7 @@ public class AppOpsManager { OPSTR_INTERACT_ACROSS_PROFILES, OPSTR_ACTIVATE_PLATFORM_VPN, OPSTR_LOADER_USAGE_STATS, - OPSTR_ACCESS_CALL_AUDIO, + "", // deprecated OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER, }; @@ -1819,7 +1816,7 @@ public class AppOpsManager { "INTERACT_ACROSS_PROFILES", "ACTIVATE_PLATFORM_VPN", "LOADER_USAGE_STATS", - "ACCESS_CALL_AUDIO", + "deprecated", "AUTO_REVOKE_PERMISSIONS_IF_UNUSED", "AUTO_REVOKE_MANAGED_BY_INSTALLER", }; @@ -1926,7 +1923,7 @@ public class AppOpsManager { android.Manifest.permission.INTERACT_ACROSS_PROFILES, null, // no permission for OP_ACTIVATE_PLATFORM_VPN android.Manifest.permission.LOADER_USAGE_STATS, - Manifest.permission.ACCESS_CALL_AUDIO, + null, // deprecated operation null, // no permission for OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED null, // no permission for OP_AUTO_REVOKE_MANAGED_BY_INSTALLER }; @@ -2033,7 +2030,7 @@ public class AppOpsManager { null, // INTERACT_ACROSS_PROFILES null, // ACTIVATE_PLATFORM_VPN null, // LOADER_USAGE_STATS - null, // ACCESS_CALL_AUDIO + null, // deprecated operation null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED null, // AUTO_REVOKE_MANAGED_BY_INSTALLER }; @@ -2139,7 +2136,7 @@ public class AppOpsManager { null, // INTERACT_ACROSS_PROFILES null, // ACTIVATE_PLATFORM_VPN null, // LOADER_USAGE_STATS - null, // ACCESS_CALL_AUDIO + null, // deprecated operation null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED null, // AUTO_REVOKE_MANAGED_BY_INSTALLER }; @@ -2244,7 +2241,7 @@ public class AppOpsManager { AppOpsManager.MODE_DEFAULT, // INTERACT_ACROSS_PROFILES AppOpsManager.MODE_IGNORED, // ACTIVATE_PLATFORM_VPN AppOpsManager.MODE_DEFAULT, // LOADER_USAGE_STATS - AppOpsManager.MODE_DEFAULT, // ACCESS_CALL_AUDIO + AppOpsManager.MODE_IGNORED, // deprecated operation AppOpsManager.MODE_DEFAULT, // OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED AppOpsManager.MODE_ALLOWED, // OP_AUTO_REVOKE_MANAGED_BY_INSTALLER }; @@ -2353,7 +2350,7 @@ public class AppOpsManager { false, // INTERACT_ACROSS_PROFILES false, // ACTIVATE_PLATFORM_VPN false, // LOADER_USAGE_STATS - false, // ACCESS_CALL_AUDIO + false, // deprecated operation false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED false, // AUTO_REVOKE_MANAGED_BY_INSTALLER }; diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 7fc10ed090c8..833bfed573b2 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -144,9 +144,6 @@ interface IActivityManager { void attachApplication(in IApplicationThread app, long startSeq); List<ActivityManager.RunningTaskInfo> getTasks(int maxNum); @UnsupportedAppUsage - List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, int ignoreActivityType, - int ignoreWindowingMode); - @UnsupportedAppUsage void moveTaskToFront(in IApplicationThread caller, in String callingPackage, int task, int flags, in Bundle options); @UnsupportedAppUsage diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index 03717ecd4038..8b8ebe80f01f 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -155,8 +155,8 @@ interface IActivityTaskManager { boolean removeTask(int taskId); void removeAllVisibleRecentTasks(); List<ActivityManager.RunningTaskInfo> getTasks(int maxNum); - List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, int ignoreActivityType, - int ignoreWindowingMode); + List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, + boolean filterOnlyVisibleRecents); boolean shouldUpRecreateTask(in IBinder token, in String destAffinity); boolean navigateUpTo(in IBinder token, in Intent target, int resultCode, in Intent resultData); diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java index 5ebcc46aa0d8..b8ad30840173 100644 --- a/core/java/android/app/TaskEmbedder.java +++ b/core/java/android/app/TaskEmbedder.java @@ -16,6 +16,7 @@ package android.app; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY; import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; @@ -291,7 +292,7 @@ public class TaskEmbedder { * @see #startActivity(PendingIntent) */ public void startActivity(@NonNull Intent intent) { - final ActivityOptions options = prepareActivityOptions(); + final ActivityOptions options = prepareActivityOptions(null); mContext.startActivity(intent, options.toBundle()); } @@ -304,7 +305,7 @@ public class TaskEmbedder { * @see #startActivity(PendingIntent) */ public void startActivity(@NonNull Intent intent, UserHandle user) { - final ActivityOptions options = prepareActivityOptions(); + final ActivityOptions options = prepareActivityOptions(null); mContext.startActivityAsUser(intent, options.toBundle(), user); } @@ -316,7 +317,7 @@ public class TaskEmbedder { * @see #startActivity(Intent) */ public void startActivity(@NonNull PendingIntent pendingIntent) { - final ActivityOptions options = prepareActivityOptions(); + final ActivityOptions options = prepareActivityOptions(null); try { pendingIntent.send(null /* context */, 0 /* code */, null /* intent */, null /* onFinished */, null /* handler */, null /* requiredPermission */, @@ -337,8 +338,7 @@ public class TaskEmbedder { */ public void startActivity(@NonNull PendingIntent pendingIntent, @Nullable Intent fillInIntent, @NonNull ActivityOptions options) { - - options.setLaunchDisplayId(mVirtualDisplay.getDisplay().getDisplayId()); + prepareActivityOptions(options); try { pendingIntent.send(mContext, 0 /* code */, fillInIntent, null /* onFinished */, null /* handler */, null /* requiredPermission */, @@ -364,21 +364,25 @@ public class TaskEmbedder { @NonNull ActivityOptions options, @Nullable Rect sourceBounds) { LauncherApps service = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE); - options.setLaunchDisplayId(mVirtualDisplay.getDisplay().getDisplayId()); + prepareActivityOptions(options); service.startShortcut(shortcut, sourceBounds, options.toBundle()); } /** - * Check if container is ready to launch and create {@link ActivityOptions} to target the - * virtual display. + * Check if container is ready to launch and modify {@param options} to target the virtual + * display, creating them if necessary. */ - private ActivityOptions prepareActivityOptions() { + private ActivityOptions prepareActivityOptions(ActivityOptions options) { if (mVirtualDisplay == null) { throw new IllegalStateException( "Trying to start activity before ActivityView is ready."); } - final ActivityOptions options = ActivityOptions.makeBasic(); + if (options == null) { + options = ActivityOptions.makeBasic(); + } options.setLaunchDisplayId(getDisplayId()); + options.setLaunchWindowingMode(WINDOWING_MODE_MULTI_WINDOW); + options.setTaskAlwaysOnTop(true); return options; } diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 31c3232f4714..9cf6569a6220 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -307,19 +307,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall try { result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri)); } catch (Exception e) { - Parcel parcel = Parcel.obtain(); - try { - try { - parcel.writeException(e); - } catch (Exception ex) { - // getType threw an unparcelable exception. Wrap the message into - // a parcelable exception type - parcel.writeException(new IllegalStateException(e.getMessage())); - } - result.putByteArray(ContentResolver.REMOTE_CALLBACK_ERROR, parcel.marshall()); - } finally { - parcel.recycle(); - } + putExceptionInBundle(result, ContentResolver.REMOTE_CALLBACK_ERROR, e); } callback.sendResult(result); } @@ -602,8 +590,12 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall public void canonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri, RemoteCallback callback) { final Bundle result = new Bundle(); - result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, - canonicalize(callingPkg, attributionTag, uri)); + try { + result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, + canonicalize(callingPkg, attributionTag, uri)); + } catch (Exception e) { + putExceptionInBundle(result, ContentResolver.REMOTE_CALLBACK_ERROR, e); + } callback.sendResult(result); } @@ -717,6 +709,22 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall return AppOpsManager.MODE_ALLOWED; } + + private void putExceptionInBundle(Bundle bundle, String key, Exception e) { + Parcel parcel = Parcel.obtain(); + try { + try { + parcel.writeException(e); + } catch (Exception ex) { + // getType threw an unparcelable exception. Wrap the message into + // a parcelable exception type + parcel.writeException(new IllegalStateException(e.getMessage())); + } + bundle.putByteArray(key, parcel.marshall()); + } finally { + parcel.recycle(); + } + } } boolean checkUser(int pid, int uid, Context context) { diff --git a/core/java/android/content/pm/DataLoaderParams.java b/core/java/android/content/pm/DataLoaderParams.java index 99c0907f1844..a791026d44cd 100644 --- a/core/java/android/content/pm/DataLoaderParams.java +++ b/core/java/android/content/pm/DataLoaderParams.java @@ -17,12 +17,8 @@ package android.content.pm; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.ComponentName; -import android.os.ParcelFileDescriptor; - -import java.util.Map; /** * This class represents the parameters used to configure a Data Loader. @@ -44,7 +40,7 @@ public class DataLoaderParams { */ public static final @NonNull DataLoaderParams forStreaming(@NonNull ComponentName componentName, @NonNull String arguments) { - return new DataLoaderParams(DataLoaderType.STREAMING, componentName, arguments, null); + return new DataLoaderParams(DataLoaderType.STREAMING, componentName, arguments); } /** @@ -55,29 +51,17 @@ public class DataLoaderParams { */ public static final @NonNull DataLoaderParams forIncremental( @NonNull ComponentName componentName, @NonNull String arguments) { - return new DataLoaderParams(DataLoaderType.INCREMENTAL, componentName, arguments, null); + return new DataLoaderParams(DataLoaderType.INCREMENTAL, componentName, arguments); } /** @hide */ public DataLoaderParams(@NonNull @DataLoaderType int type, @NonNull ComponentName componentName, - @NonNull String arguments, @Nullable Map<String, ParcelFileDescriptor> namedFds) { + @NonNull String arguments) { DataLoaderParamsParcel data = new DataLoaderParamsParcel(); data.type = type; data.packageName = componentName.getPackageName(); data.className = componentName.getClassName(); data.arguments = arguments; - if (namedFds == null || namedFds.isEmpty()) { - data.dynamicArgs = new NamedParcelFileDescriptor[0]; - } else { - data.dynamicArgs = new NamedParcelFileDescriptor[namedFds.size()]; - int i = 0; - for (Map.Entry<String, ParcelFileDescriptor> namedFd : namedFds.entrySet()) { - data.dynamicArgs[i] = new NamedParcelFileDescriptor(); - data.dynamicArgs[i].name = namedFd.getKey(); - data.dynamicArgs[i].fd = namedFd.getValue(); - i += 1; - } - } mData = data; } diff --git a/core/java/android/content/pm/DataLoaderParamsParcel.aidl b/core/java/android/content/pm/DataLoaderParamsParcel.aidl index e05843b4d4e9..d40012fd5718 100644 --- a/core/java/android/content/pm/DataLoaderParamsParcel.aidl +++ b/core/java/android/content/pm/DataLoaderParamsParcel.aidl @@ -17,7 +17,6 @@ package android.content.pm; import android.content.pm.DataLoaderType; -import android.content.pm.NamedParcelFileDescriptor; /** * Class for holding data loader configuration parameters. @@ -28,5 +27,4 @@ parcelable DataLoaderParamsParcel { @utf8InCpp String packageName; @utf8InCpp String className; @utf8InCpp String arguments; - NamedParcelFileDescriptor[] dynamicArgs; } diff --git a/core/java/android/content/pm/NamedParcelFileDescriptor.aidl b/core/java/android/content/pm/NamedParcelFileDescriptor.aidl deleted file mode 100644 index 68dd5f54654b..000000000000 --- a/core/java/android/content/pm/NamedParcelFileDescriptor.aidl +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.content.pm; - -import android.os.ParcelFileDescriptor; - -/** - * A named ParcelFileDescriptor. - * @hide - */ -parcelable NamedParcelFileDescriptor { - @utf8InCpp String name; - ParcelFileDescriptor fd; -} diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 50bee854c027..1e0b2e358e17 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -1118,6 +1118,7 @@ public class PackageInstaller { * {@hide} */ @SystemApi + @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2) public @Nullable DataLoaderParams getDataLoaderParams() { try { DataLoaderParamsParcel data = mSession.getDataLoaderParams(); @@ -1157,6 +1158,7 @@ public class PackageInstaller { * {@hide} */ @SystemApi + @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2) public void addFile(@FileLocation int location, @NonNull String name, long lengthBytes, @NonNull byte[] metadata, @Nullable byte[] signature) { try { @@ -1180,6 +1182,7 @@ public class PackageInstaller { * {@hide} */ @SystemApi + @RequiresPermission(android.Manifest.permission.USE_INSTALLER_V2) public void removeFile(@FileLocation int location, @NonNull String name) { try { mSession.removeFile(location, name); @@ -1927,7 +1930,9 @@ public class PackageInstaller { * {@hide} */ @SystemApi - @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) + @RequiresPermission(allOf = { + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.USE_INSTALLER_V2}) public void setDataLoaderParams(@NonNull DataLoaderParams dataLoaderParams) { this.dataLoaderParams = dataLoaderParams; } diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 6daded4ee641..782fff2f69e0 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -60,7 +60,6 @@ import android.text.method.MovementMethod; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Printer; -import android.util.Size; import android.view.Gravity; import android.view.KeyCharacterMap; import android.view.KeyEvent; @@ -1480,8 +1479,8 @@ public class InputMethodService extends AbstractInputMethodService { */ public int getMaxWidth() { final WindowManager windowManager = getSystemService(WindowManager.class); - final Size windowSize = windowManager.getCurrentWindowMetrics().getSize(); - return windowSize.getWidth(); + final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds(); + return windowBounds.width(); } /** diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2a323e5ec97d..7332ede0b997 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -705,6 +705,36 @@ public class ConnectivityManager { @Deprecated public static final int TYPE_TEST = 18; // TODO: Remove this once NetworkTypes are unused. + /** + * @deprecated Use {@link NetworkCapabilities} instead. + * @hide + */ + @Deprecated + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_NONE, + TYPE_MOBILE, + TYPE_WIFI, + TYPE_MOBILE_MMS, + TYPE_MOBILE_SUPL, + TYPE_MOBILE_DUN, + TYPE_MOBILE_HIPRI, + TYPE_WIMAX, + TYPE_BLUETOOTH, + TYPE_DUMMY, + TYPE_ETHERNET, + TYPE_MOBILE_FOTA, + TYPE_MOBILE_IMS, + TYPE_MOBILE_CBS, + TYPE_WIFI_P2P, + TYPE_MOBILE_IA, + TYPE_MOBILE_EMERGENCY, + TYPE_PROXY, + TYPE_VPN, + TYPE_TEST + }) + public @interface LegacyNetworkType {} + // Deprecated constants for return values of startUsingNetworkFeature. They used to live // in com.android.internal.telephony.PhoneConstants until they were made inaccessible. private static final int DEPRECATED_PHONE_CONSTANT_APN_ALREADY_ACTIVE = 0; diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 5c754a1b9733..8119df921745 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -16,6 +16,8 @@ package android.net; +import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; @@ -32,18 +34,52 @@ import android.util.Log; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; /** - * A Utility class for handling for communicating between bearer-specific + * A utility class for handling for communicating between bearer-specific * code and ConnectivityService. * + * An agent manages the life cycle of a network. A network starts its + * life cycle when {@link register} is called on NetworkAgent. The network + * is then connecting. When full L3 connectivity has been established, + * the agent shoud call {@link setConnected} to inform the system that + * this network is ready to use. When the network disconnects its life + * ends and the agent should call {@link unregister}, at which point the + * system will clean up and free resources. + * Any reconnection becomes a new logical network, so after a network + * is disconnected the agent cannot be used any more. Network providers + * should create a new NetworkAgent instance to handle new connections. + * * A bearer may have more than one NetworkAgent if it can simultaneously * support separate networks (IMS / Internet / MMS Apns on cellular, or * perhaps connections with different SSID or P2P for Wi-Fi). * + * This class supports methods to start and stop sending keepalive packets. + * Keepalive packets are typically sent at periodic intervals over a network + * with NAT when there is no other traffic to avoid the network forcefully + * closing the connection. NetworkAgents that manage technologies that + * have hardware support for keepalive should implement the related + * methods to save battery life. NetworkAgent that cannot get support + * without waking up the CPU should not, as this would be prohibitive in + * terms of battery - these agents should simply not override the related + * methods, which results in the implementation returning + * {@link SocketKeepalive.ERROR_UNSUPPORTED} as appropriate. + * + * Keepalive packets need to be sent at relatively frequent intervals + * (a few seconds to a few minutes). As the contents of keepalive packets + * depend on the current network status, hardware needs to be configured + * to send them and has a limited amount of memory to do so. The HAL + * formalizes this as slots that an implementation can configure to send + * the correct packets. Devices typically have a small number of slots + * per radio technology, and the specific number of slots for each + * technology is specified in configuration files. + * {@see SocketKeepalive} for details. + * * @hide */ @SystemApi @@ -65,7 +101,7 @@ public abstract class NetworkAgent { private final String LOG_TAG; private static final boolean DBG = true; private static final boolean VDBG = false; - private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>(); + private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>(); private volatile long mLastBwRefreshTime = 0; private static final long BW_REFRESH_MIN_WIN_MS = 500; private boolean mBandwidthUpdateScheduled = false; @@ -74,6 +110,8 @@ public abstract class NetworkAgent { // into the internal API of ConnectivityService. @NonNull private NetworkInfo mNetworkInfo; + @NonNull + private final Object mRegisterLock = new Object(); /** * The ID of the {@link NetworkProvider} that created this object, or @@ -158,6 +196,14 @@ public abstract class NetworkAgent { */ public static final int VALIDATION_STATUS_NOT_VALID = 2; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "VALIDATION_STATUS_" }, value = { + VALIDATION_STATUS_VALID, + VALIDATION_STATUS_NOT_VALID + }) + public @interface ValidationStatus {} + // TODO: remove. /** @hide */ public static final int VALID_NETWORK = 1; @@ -202,7 +248,7 @@ public abstract class NetworkAgent { * Sent by ConnectivityService to the NetworkAgent to request that the specified packet be sent * periodically on the given interval. * - * arg1 = the slot number of the keepalive to start + * arg1 = the hardware slot number of the keepalive to start * arg2 = interval in seconds * obj = KeepalivePacketData object describing the data to be sent * @@ -214,7 +260,7 @@ public abstract class NetworkAgent { /** * Requests that the specified keepalive packet be stopped. * - * arg1 = slot number of the keepalive to stop. + * arg1 = hardware slot number of the keepalive to stop. * * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics. * @hide @@ -229,7 +275,7 @@ public abstract class NetworkAgent { * This is also sent by KeepaliveTracker to the app's {@link SocketKeepalive}, * so that the app's {@link SocketKeepalive.Callback} methods can be called. * - * arg1 = slot number of the keepalive + * arg1 = hardware slot number of the keepalive * arg2 = error code * @hide */ @@ -259,7 +305,7 @@ public abstract class NetworkAgent { * remote site will send ACK packets in response to the keepalive packets, the firmware also * needs to be configured to properly filter the ACKs to prevent the system from waking up. * This does not happen with UDP, so this message is TCP-specific. - * arg1 = slot number of the keepalive to filter for. + * arg1 = hardware slot number of the keepalive to filter for. * obj = the keepalive packet to send repeatedly. * @hide */ @@ -268,7 +314,7 @@ public abstract class NetworkAgent { /** * Sent by the KeepaliveTracker to NetworkAgent to remove a packet filter. See * {@link #CMD_ADD_KEEPALIVE_PACKET_FILTER}. - * arg1 = slot number of the keepalive packet filter to remove. + * arg1 = hardware slot number of the keepalive packet filter to remove. * @hide */ public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17; @@ -441,7 +487,15 @@ public abstract class NetworkAgent { + (msg.arg1 == VALID_NETWORK ? "VALID, " : "INVALID, ") + redirectUrl); } - onValidationStatus(msg.arg1 /* status */, redirectUrl); + Uri uri = null; + try { + if (null != redirectUrl) { + uri = Uri.parse(redirectUrl); + } + } catch (Exception e) { + Log.wtf(LOG_TAG, "Surprising URI : " + redirectUrl, e); + } + onValidationStatus(msg.arg1 /* status */, uri); break; } case CMD_SAVE_ACCEPT_UNVALIDATED: { @@ -489,19 +543,29 @@ public abstract class NetworkAgent { /** * Register this network agent with ConnectivityService. + * + * This method can only be called once per network agent. + * * @return the Network associated with this network agent (which can also be obtained later * by calling getNetwork() on this agent). + * @throws IllegalStateException thrown by the system server if this network agent is + * already registered. */ @NonNull public Network register() { if (VDBG) log("Registering NetworkAgent"); final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context .getSystemService(Context.CONNECTIVITY_SERVICE); - mNetwork = cm.registerNetworkAgent(new Messenger(mHandler), - new NetworkInfo(mInitialConfiguration.info), - mInitialConfiguration.properties, mInitialConfiguration.capabilities, - mInitialConfiguration.score, mInitialConfiguration.config, providerId); - mInitialConfiguration = null; // All this memory can now be GC'd + synchronized (mRegisterLock) { + if (mNetwork != null) { + throw new IllegalStateException("Agent already registered"); + } + mNetwork = cm.registerNetworkAgent(new Messenger(mHandler), + new NetworkInfo(mInitialConfiguration.info), + mInitialConfiguration.properties, mInitialConfiguration.capabilities, + mInitialConfiguration.score, mInitialConfiguration.config, providerId); + mInitialConfiguration = null; // All this memory can now be GC'd + } return mNetwork; } @@ -544,13 +608,14 @@ public abstract class NetworkAgent { * Must be called by the agent when the network's {@link LinkProperties} change. * @param linkProperties the new LinkProperties. */ - public void sendLinkProperties(@NonNull LinkProperties linkProperties) { + public final void sendLinkProperties(@NonNull LinkProperties linkProperties) { Objects.requireNonNull(linkProperties); queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties)); } /** * Inform ConnectivityService that this agent has now connected. + * Call {@link #unregister} to disconnect. */ public void setConnected() { if (mIsLegacy) { @@ -569,8 +634,7 @@ public abstract class NetworkAgent { */ public void unregister() { if (mIsLegacy) { - throw new UnsupportedOperationException( - "Legacy agents can't call unregister."); + throw new UnsupportedOperationException("Legacy agents can't call unregister."); } mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, mNetworkInfo); @@ -626,7 +690,7 @@ public abstract class NetworkAgent { * @hide TODO: expose something better. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) - public void sendNetworkInfo(NetworkInfo networkInfo) { + public final void sendNetworkInfo(NetworkInfo networkInfo) { if (!mIsLegacy) { throw new UnsupportedOperationException("Only legacy agents can call sendNetworkInfo."); } @@ -637,7 +701,7 @@ public abstract class NetworkAgent { * Must be called by the agent when the network's {@link NetworkCapabilities} change. * @param networkCapabilities the new NetworkCapabilities. */ - public void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { + public final void sendNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { Objects.requireNonNull(networkCapabilities); mBandwidthUpdatePending.set(false); mLastBwRefreshTime = System.currentTimeMillis(); @@ -647,9 +711,10 @@ public abstract class NetworkAgent { /** * Must be called by the agent to update the score of this network. - * @param score the new score. + * + * @param score the new score, between 0 and 99. */ - public void sendNetworkScore(int score) { + public final void sendNetworkScore(@IntRange(from = 0, to = 99) int score) { if (score < 0) { throw new IllegalArgumentException("Score must be >= 0"); } @@ -737,11 +802,11 @@ public abstract class NetworkAgent { * subsequent attempts to validate connectivity that fail. * * @param status one of {@code VALIDATION_STATUS_VALID} or {@code VALIDATION_STATUS_NOT_VALID}. - * @param redirectUrl If Internet connectivity is being redirected (e.g., on a captive portal), + * @param redirectUri If Internet connectivity is being redirected (e.g., on a captive portal), * this is the destination the probes are being redirected to, otherwise {@code null}. */ - public void onValidationStatus(int status, @Nullable String redirectUrl) { - networkStatus(status, redirectUrl); + public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) { + networkStatus(status, redirectUri.toString()); } /** @hide TODO delete once subclasses have moved to onValidationStatus */ protected void networkStatus(int status, String redirectUrl) { @@ -770,7 +835,12 @@ public abstract class NetworkAgent { * @param intervalSeconds the interval between packets * @param packet the packet to send. */ - public void onStartSocketKeepalive(int slot, int intervalSeconds, + // seconds is from SocketKeepalive.MIN_INTERVAL_SEC to MAX_INTERVAL_SEC, but these should + // not be exposed as constants because they may change in the future (API guideline 4.8) + // and should have getters if exposed at all. Getters can't be used in the annotation, + // so the values unfortunately need to be copied. + public void onStartSocketKeepalive(int slot, + @IntRange(from = 10, to = 3600) int intervalSeconds, @NonNull KeepalivePacketData packet) { Message msg = mHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, slot, intervalSeconds, packet); @@ -801,9 +871,11 @@ public abstract class NetworkAgent { * Must be called by the agent when a socket keepalive event occurs. * * @param slot the hardware slot on which the event occurred. - * @param event the event that occurred. + * @param event the event that occurred, as one of the SocketKeepalive.ERROR_* + * or SocketKeepalive.SUCCESS constants. */ - public void sendSocketKeepaliveEvent(int slot, int event) { + public final void sendSocketKeepaliveEvent(int slot, + @SocketKeepalive.KeepaliveEvent int event) { queueOrSendMessage(EVENT_SOCKET_KEEPALIVE, slot, event); } /** @hide TODO delete once callers have moved to sendSocketKeepaliveEvent */ @@ -845,9 +917,18 @@ public abstract class NetworkAgent { } /** - * Called by ConnectivityService to inform this network transport of signal strength thresholds + * Called by ConnectivityService to inform this network agent of signal strength thresholds * that when crossed should trigger a system wakeup and a NetworkCapabilities update. * + * When the system updates the list of thresholds that should wake up the CPU for a + * given agent it will call this method on the agent. The agent that implement this + * should implement it in hardware so as to ensure the CPU will be woken up on breach. + * Agents are expected to react to a breach by sending an updated NetworkCapabilities + * object with the appropriate signal strength to sendNetworkCapabilities. + * + * The specific units are bearer-dependent. See details on the units and requests in + * {@link NetworkCapabilities.Builder#setSignalStrength}. + * * @param thresholds the array of thresholds that should trigger wakeups. */ public void onSignalStrengthThresholdsUpdated(@NonNull int[] thresholds) { diff --git a/core/java/android/net/NetworkAgentConfig.java b/core/java/android/net/NetworkAgentConfig.java index ca9328a713f0..fee868a93be4 100644 --- a/core/java/android/net/NetworkAgentConfig.java +++ b/core/java/android/net/NetworkAgentConfig.java @@ -155,6 +155,7 @@ public final class NetworkAgentConfig implements Parcelable { /** * @return the legacy type */ + @ConnectivityManager.LegacyNetworkType public int getLegacyType() { return legacyType; } @@ -206,7 +207,7 @@ public final class NetworkAgentConfig implements Parcelable { /** * Builder class to facilitate constructing {@link NetworkAgentConfig} objects. */ - public static class Builder { + public static final class Builder { private final NetworkAgentConfig mConfig = new NetworkAgentConfig(); /** diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 964f13f39ec6..798856d13b1d 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -473,9 +473,7 @@ public class NetworkRequest implements Parcelable { * * @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not * satisfy any request. - * @hide */ - @SystemApi public boolean satisfiedBy(@Nullable NetworkCapabilities nc) { return networkCapabilities.satisfiedByNetworkCapabilities(nc); } diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java index fc9a8f63c131..8ff8f4c48c32 100644 --- a/core/java/android/net/SocketKeepalive.java +++ b/core/java/android/net/SocketKeepalive.java @@ -109,6 +109,16 @@ public abstract class SocketKeepalive implements AutoCloseable { }) public @interface ErrorCode {} + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(value = { + SUCCESS, + ERROR_INVALID_LENGTH, + ERROR_UNSUPPORTED, + ERROR_INSUFFICIENT_RESOURCES + }) + public @interface KeepaliveEvent {} + /** * The minimum interval in seconds between keepalive packet transmissions. * diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java index d60820ef0f57..8cdcd49cb2cc 100644 --- a/core/java/android/os/RecoverySystem.java +++ b/core/java/android/os/RecoverySystem.java @@ -665,15 +665,17 @@ public class RecoverySystem { * the preparation for unattended update is reset. * * @param context the Context to use. - * @throws IOException if there were any errors setting up unattended update + * @throws IOException if there were any errors clearing the unattended update state * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.RECOVERY) - public static boolean clearPrepareForUnattendedUpdate(@NonNull Context context) + public static void clearPrepareForUnattendedUpdate(@NonNull Context context) throws IOException { RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE); - return rs.clearLskf(); + if (!rs.clearLskf()) { + throw new IOException("could not reset unattended update state"); + } } /** @@ -684,21 +686,22 @@ public class RecoverySystem { * @param context the Context to use. * @param updateToken the token used to call {@link #prepareForUnattendedUpdate} before * @param reason the reboot reason to give to the {@link PowerManager} - * @throws IOException if there were any errors setting up unattended update - * @return false if the reboot couldn't proceed because the device wasn't ready for an + * @throws IOException if the reboot couldn't proceed because the device wasn't ready for an * unattended reboot or if the {@code updateToken} did not match the previously * given token * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.RECOVERY) - public static boolean rebootAndApply(@NonNull Context context, @NonNull String updateToken, + public static void rebootAndApply(@NonNull Context context, @NonNull String updateToken, @NonNull String reason) throws IOException { if (updateToken == null) { throw new NullPointerException("updateToken == null"); } RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE); - return rs.rebootWithLskf(updateToken, reason); + if (!rs.rebootWithLskf(updateToken, reason)) { + throw new IOException("system not prepared to apply update"); + } } /** diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java index aa89b515adc6..ca861577ab37 100644 --- a/core/java/android/os/VibrationEffect.java +++ b/core/java/android/os/VibrationEffect.java @@ -961,7 +961,7 @@ public abstract class VibrationEffect implements Parcelable { * * @see VibrationEffect#startComposition() */ - public static class Composition { + public static final class Composition { /** @hide */ @IntDef(prefix = { "PRIMITIVE_" }, value = { PRIMITIVE_CLICK, @@ -1020,6 +1020,8 @@ public abstract class VibrationEffect implements Parcelable { private ArrayList<PrimitiveEffect> mEffects = new ArrayList<>(); + Composition() { } + /** * Add a haptic primitive to the end of the current composition. * @@ -1030,7 +1032,7 @@ public abstract class VibrationEffect implements Parcelable { * * @return The {@link Composition} object to enable adding multiple primitives in one chain. */ - @Nullable + @NonNull public Composition addPrimitive(@Primitive int primitiveId) { addPrimitive(primitiveId, /*scale*/ 1.0f, /*delay*/ 0); return this; @@ -1046,7 +1048,7 @@ public abstract class VibrationEffect implements Parcelable { * * @return The {@link Composition} object to enable adding multiple primitives in one chain. */ - @Nullable + @NonNull public Composition addPrimitive(@Primitive int primitiveId, @FloatRange(from = 0f, to = 1f) float scale) { addPrimitive(primitiveId, scale, /*delay*/ 0); @@ -1058,11 +1060,11 @@ public abstract class VibrationEffect implements Parcelable { * * @param primitiveId The primitive to add * @param scale The scale to apply to the intensity of the primitive. - * @param delay The amount of time, in milliseconds, to wait before playing the prior + * @param delay The amount of time, in milliseconds, to wait between playing the prior * primitive and this one * @return The {@link Composition} object to enable adding multiple primitives in one chain. */ - @Nullable + @NonNull public Composition addPrimitive(@Primitive int primitiveId, @FloatRange(from = 0f, to = 1f) float scale, @IntRange(from = 0) int delay) { mEffects.add(new PrimitiveEffect(checkPrimitive(primitiveId), scale, delay)); diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index d4da7a84d2a1..f7183b14a97a 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -351,7 +351,7 @@ public abstract class Vibrator { * what it supports. */ @Nullable - public Boolean areAllEffectsSupported( + public final Boolean areAllEffectsSupported( @NonNull @VibrationEffect.EffectType int... effectIds) { for (boolean supported : areEffectsSupported(effectIds)) { if (!supported) { @@ -384,7 +384,7 @@ public abstract class Vibrator { * @param primitiveIds Which primitives to query for. * @return Whether primitives effects are supported. */ - public boolean areAllPrimitivesSupported( + public final boolean areAllPrimitivesSupported( @NonNull @VibrationEffect.Composition.Primitive int... primitiveIds) { for (boolean supported : arePrimitivesSupported(primitiveIds)) { if (!supported) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index bbcb9d9249af..d2a03f0ff166 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6589,11 +6589,9 @@ public final class Settings { "accessibility_shortcut_target_service"; /** - * Setting specifying the accessibility services, accessibility shortcut targets, - * or features to be toggled via the accessibility button in the navigation bar. - * - * <p> This is a colon-separated string list which contains the flattened - * {@link ComponentName} and the class name of a system class implementing a supported + * Setting specifying the accessibility service or feature to be toggled via the + * accessibility button in the navigation bar. This is either a flattened + * {@link ComponentName} or the class name of a system class implementing a supported * accessibility feature. * @hide */ @@ -6602,15 +6600,14 @@ public final class Settings { /** * Setting specifying the accessibility services, accessibility shortcut targets, - * or features to be toggled via the long press accessibility button in the navigation bar. + * or features to be toggled via the accessibility button in the navigation bar. * * <p> This is a colon-separated string list which contains the flattened * {@link ComponentName} and the class name of a system class implementing a supported * accessibility feature. * @hide */ - public static final String ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS = - "accessibility_button_long_press_targets"; + public static final String ACCESSIBILITY_BUTTON_TARGETS = "accessibility_button_targets"; /** * The system class name of magnification controller which is a target to be toggled via @@ -6775,8 +6772,8 @@ public final class Settings { * zoom in the display content and is targeted to low vision users. The current * magnification scale is controlled by {@link #ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE}. * - * @deprecated Use {@link #ACCESSIBILITY_BUTTON_TARGET_COMPONENT} instead. - * {@link #ACCESSIBILITY_BUTTON_TARGET_COMPONENT} holds the magnification system class name + * @deprecated Use {@link #ACCESSIBILITY_BUTTON_TARGETS} instead. + * {@link #ACCESSIBILITY_BUTTON_TARGETS} holds the magnification system class name * when navigation bar magnification is enabled. * @hide */ diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java index 37a75f0e9e5a..10f526d6565c 100644 --- a/core/java/android/service/controls/actions/ControlAction.java +++ b/core/java/android/service/controls/actions/ControlAction.java @@ -136,7 +136,8 @@ public abstract class ControlAction { /** * Response code for the {@code consumer} in * {@link ControlsProviderService#performControlAction} indicating that in order for the action - * to be performed, acknowledgment from the user is required. + * to be performed, acknowledgment from the user is required. Any non-empty string returned + * from {@link #getChallengeValue} shall be treated as a positive acknowledgment. */ public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 3; /** diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java index 0170726b31d6..c047dc0d07c7 100644 --- a/core/java/android/service/dataloader/DataLoaderService.java +++ b/core/java/android/service/dataloader/DataLoaderService.java @@ -29,7 +29,6 @@ import android.content.pm.IDataLoader; import android.content.pm.IDataLoaderStatusListener; import android.content.pm.InstallationFile; import android.content.pm.InstallationFileParcel; -import android.content.pm.NamedParcelFileDescriptor; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.util.ExceptionUtils; @@ -133,16 +132,6 @@ public abstract class DataLoaderService extends Service { } } } - if (params.dynamicArgs != null) { - NamedParcelFileDescriptor[] fds = params.dynamicArgs; - for (NamedParcelFileDescriptor nfd : fds) { - try { - nfd.fd.close(); - } catch (IOException e) { - Slog.e(TAG, "Failed to close DynamicArgs parcel file descriptor " + e); - } - } - } } } diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index dffcafe1de0e..0ccb1e055c46 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -57,8 +57,8 @@ import java.util.List; * <li>The application display area specifies the part of the display that may contain * an application window, excluding the system decorations. The application display area may * be smaller than the real display area because the system subtracts the space needed - * for decor elements such as the status bar. Use {@link WindowMetrics#getSize()} to query the - * application window size.</li> + * for decor elements such as the status bar. Use {@link WindowMetrics#getBounds()} to query the + * application window bounds.</li> * <li>The real display area specifies the part of the display that contains content * including the system decorations. Even so, the real display area may be smaller than the * physical size of the display if the window manager is emulating a smaller display @@ -673,7 +673,7 @@ public final class Display { * * @param outSize A {@link Point} object to receive the size information. * @deprecated Use {@link WindowManager#getCurrentWindowMetrics()} to obtain an instance of - * {@link WindowMetrics} and use {@link WindowMetrics#getSize()} instead. + * {@link WindowMetrics} and use {@link WindowMetrics#getBounds()} instead. */ @Deprecated public void getSize(Point outSize) { @@ -689,7 +689,7 @@ public final class Display { * Gets the size of the display as a rectangle, in pixels. * * @param outSize A {@link Rect} object to receive the size information. - * @deprecated Use {@link WindowMetrics#getSize()} to get the dimensions of the application + * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application * window area. */ @Deprecated @@ -755,7 +755,7 @@ public final class Display { } /** - * @deprecated Use {@link WindowMetrics#getSize()} instead. + * @deprecated Use {@link WindowMetrics#getBounds#width()} instead. */ @Deprecated public int getWidth() { @@ -766,7 +766,7 @@ public final class Display { } /** - * @deprecated Use {@link WindowMetrics#getSize()} instead. + * @deprecated Use {@link WindowMetrics#getBounds()#height()} instead. */ @Deprecated public int getHeight() { @@ -1105,7 +1105,7 @@ public final class Display { * </p> * * @param outMetrics A {@link DisplayMetrics} object to receive the metrics. - * @deprecated Use {@link WindowMetrics#getSize()} to get the dimensions of the application + * @deprecated Use {@link WindowMetrics#getBounds()} to get the dimensions of the application * window area, and {@link Configuration#densityDpi} to get the current density. */ @Deprecated diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index d69357bc503d..4922917c911c 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3475,7 +3475,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Flag indicating the field should not have yellow highlight when autofilled. */ - private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x100; + private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200; /* End of masks for mPrivateFlags4 */ diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index 04260c47eda3..4bea623716dc 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -23,11 +23,11 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; +import android.graphics.Rect; import android.os.Build; import android.os.RemoteException; import android.provider.Settings; import android.util.DisplayMetrics; -import android.util.Size; import android.util.SparseArray; import android.util.TypedValue; @@ -410,8 +410,8 @@ public class ViewConfiguration { // Size of the screen in bytes, in ARGB_8888 format final WindowManager windowManager = context.getSystemService(WindowManager.class); - final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize(); - mMaximumDrawingCacheSize = 4 * maxWindowSize.getWidth() * maxWindowSize.getHeight(); + final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds(); + mMaximumDrawingCacheSize = 4 * maxWindowBounds.width() * maxWindowBounds.height(); mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f); mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f); diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 8bf1ade876ca..316a5f2c88d2 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -35,7 +35,6 @@ import android.graphics.Region; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; -import android.util.Size; import com.android.internal.os.IResultReceiver; @@ -220,7 +219,7 @@ public final class WindowManagerImpl implements WindowManager { final Context context = mParentWindow != null ? mParentWindow.getContext() : mContext; final Rect bounds = getCurrentBounds(context); - return new WindowMetrics(toSize(bounds), computeWindowInsets(bounds)); + return new WindowMetrics(bounds, computeWindowInsets(bounds)); } private static Rect getCurrentBounds(Context context) { @@ -232,11 +231,7 @@ public final class WindowManagerImpl implements WindowManager { @Override public WindowMetrics getMaximumWindowMetrics() { final Rect maxBounds = getMaximumBounds(); - return new WindowMetrics(toSize(maxBounds), computeWindowInsets(maxBounds)); - } - - private Size toSize(Rect frame) { - return new Size(frame.width(), frame.height()); + return new WindowMetrics(maxBounds, computeWindowInsets(maxBounds)); } private Rect getMaximumBounds() { diff --git a/core/java/android/view/WindowMetrics.java b/core/java/android/view/WindowMetrics.java index ab5a06eb99de..86ef87997a07 100644 --- a/core/java/android/view/WindowMetrics.java +++ b/core/java/android/view/WindowMetrics.java @@ -18,10 +18,10 @@ package android.view; import android.annotation.NonNull; import android.graphics.Point; -import android.util.Size; +import android.graphics.Rect; /** - * Metrics about a Window, consisting of the size and {@link WindowInsets}. + * Metrics about a Window, consisting of the bounds and {@link WindowInsets}. * <p> * This is usually obtained from {@link WindowManager#getCurrentWindowMetrics()} and * {@link WindowManager#getMaximumWindowMetrics()}. @@ -31,21 +31,22 @@ import android.util.Size; * @see WindowManager#getMaximumWindowMetrics() */ public final class WindowMetrics { - private final @NonNull Size mSize; + private final @NonNull Rect mBounds; private final @NonNull WindowInsets mWindowInsets; - public WindowMetrics(@NonNull Size size, @NonNull WindowInsets windowInsets) { - mSize = size; + public WindowMetrics(@NonNull Rect bounds, @NonNull WindowInsets windowInsets) { + mBounds = bounds; mWindowInsets = windowInsets; } /** - * Returns the size of the window. + * Returns the bounds of the area associated with this window or visual context. * <p> - * <b>Note that this reports a different size than {@link Display#getSize(Point)}.</b> - * This method reports the window size including all system bars area, while - * {@link Display#getSize(Point)} reports the area excluding navigation bars and display cutout - * areas. The value reported by {@link Display#getSize(Point)} can be obtained by using: + * <b>Note that the size of the reported bounds can have different size than + * {@link Display#getSize(Point)}.</b> This method reports the window size including all system + * bar areas, while {@link Display#getSize(Point)} reports the area excluding navigation bars + * and display cutout areas. The value reported by {@link Display#getSize(Point)} can be + * obtained by using: * <pre class="prettyprint"> * final WindowMetrics metrics = windowManager.getCurrentMetrics(); * // Gets all excluding insets @@ -66,16 +67,16 @@ public final class WindowMetrics { * </pre> * </p> * - * @return window size in pixel. + * @return window bounds in pixels. */ - public @NonNull Size getSize() { - return mSize; + public @NonNull Rect getBounds() { + return mBounds; } /** - * Returns the {@link WindowInsets} of the window. + * Returns the {@link WindowInsets} of the area associated with this window or visual context. * - * @return the {@link WindowInsets} of the window. + * @return the {@link WindowInsets} of the visual area. */ public @NonNull WindowInsets getWindowInsets() { return mWindowInsets; diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 39a9ed4a82e7..267a5a6561af 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -1242,9 +1242,10 @@ public final class AutofillManager { if (mLastAutofilledData.containsKey(id)) { value = view.getAutofillValue(); valueWasRead = true; + final boolean hideHighlight = mLastAutofilledData.keySet().size() == 1; if (Objects.equals(mLastAutofilledData.get(id), value)) { - view.setAutofilled(true, false); + view.setAutofilled(true, hideHighlight); } else { view.setAutofilled(false, false); mLastAutofilledData.remove(id); diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java index 8d3dc83bca0c..2ead352fd199 100644 --- a/core/java/android/view/autofill/AutofillPopupWindow.java +++ b/core/java/android/view/autofill/AutofillPopupWindow.java @@ -25,7 +25,6 @@ import android.os.IBinder; import android.os.RemoteException; import android.transition.Transition; import android.util.Log; -import android.util.Size; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewTreeObserver; @@ -129,10 +128,10 @@ public class AutofillPopupWindow extends PopupWindow { // Gravity.BOTTOM because PopupWindow base class does not expose computeGravity(). final WindowManager windowManager = anchor.getContext() .getSystemService(WindowManager.class); - final Size windowSize = windowManager.getCurrentWindowMetrics().getSize(); - width = windowSize.getWidth(); + final Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds(); + width = windowBounds.width(); if (height != LayoutParams.MATCH_PARENT) { - offsetY = windowSize.getHeight() - height; + offsetY = windowBounds.height() - height; } actualAnchor = anchor; } else if (virtualBounds != null) { diff --git a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java index c40864131a2e..51b13345a6c3 100644 --- a/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java +++ b/core/java/com/android/internal/app/AccessibilityButtonChooserActivity.java @@ -169,13 +169,41 @@ public class AccessibilityButtonChooserActivity extends Activity { private static List<AccessibilityButtonTarget> getInstalledServiceTargets( @NonNull Context context) { final List<AccessibilityButtonTarget> targets = new ArrayList<>(); - targets.addAll(getAccessibilityServiceTargets(context)); - targets.addAll(getAccessibilityActivityTargets(context)); + targets.addAll(getAccessibilityFilteredTargets(context)); targets.addAll(getWhiteListingServiceTargets(context)); return targets; } + private static List<AccessibilityButtonTarget> getAccessibilityFilteredTargets( + @NonNull Context context) { + final List<AccessibilityButtonTarget> serviceTargets = + getAccessibilityServiceTargets(context); + final List<AccessibilityButtonTarget> activityTargets = + getAccessibilityActivityTargets(context); + + for (AccessibilityButtonTarget activityTarget : activityTargets) { + serviceTargets.removeIf(serviceTarget -> { + final ComponentName serviceComponentName = + ComponentName.unflattenFromString(serviceTarget.getId()); + final ComponentName activityComponentName = + ComponentName.unflattenFromString(activityTarget.getId()); + final boolean isSamePackageName = activityComponentName.getPackageName().equals( + serviceComponentName.getPackageName()); + final boolean isSameLabel = activityTarget.getLabel().equals( + serviceTarget.getLabel()); + + return isSamePackageName && isSameLabel; + }); + } + + final List<AccessibilityButtonTarget> targets = new ArrayList<>(); + targets.addAll(serviceTargets); + targets.addAll(activityTargets); + + return targets; + } + private static List<AccessibilityButtonTarget> getAccessibilityServiceTargets( @NonNull Context context) { final AccessibilityManager ams = context.getSystemService(AccessibilityManager.class); diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index 0aeaa47ba3d8..980943ebea5a 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -22,14 +22,10 @@ import android.annotation.Nullable; import android.annotation.StyleRes; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.graphics.Point; import android.graphics.Rect; -import android.util.Size; -import android.view.Display; import android.view.Gravity; import android.view.View; import android.view.WindowManager; -import android.view.WindowMetrics; import android.widget.PopupWindow.OnDismissListener; import com.android.internal.view.menu.MenuPresenter.Callback; @@ -227,9 +223,9 @@ public class MenuPopupHelper implements MenuHelper { @NonNull private MenuPopup createPopup() { final WindowManager windowManager = mContext.getSystemService(WindowManager.class); - final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize(); + final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds(); - final int smallestWidth = Math.min(maxWindowSize.getWidth(), maxWindowSize.getHeight()); + final int smallestWidth = Math.min(maxWindowBounds.width(), maxWindowBounds.height()); final int minSmallestWidthCascading = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.cascading_menus_min_smallest_width); final boolean enableCascadingSubmenus = smallestWidth >= minSmallestWidthCascading; diff --git a/core/jni/android_media_AudioProductStrategies.cpp b/core/jni/android_media_AudioProductStrategies.cpp index 17a02b24c697..34be2a52344d 100644 --- a/core/jni/android_media_AudioProductStrategies.cpp +++ b/core/jni/android_media_AudioProductStrategies.cpp @@ -85,10 +85,23 @@ static jint convertAudioProductStrategiesFromNative( jStrategyId = static_cast<jint>(strategy.getId()); // Audio Attributes Group array - std::map<int, std::vector<AudioAttributes> > groups; + int attrGroupIndex = 0; + std::map<int /**attributesGroupIndex*/, std::vector<AudioAttributes> > groups; for (const auto &attr : strategy.getAudioAttributes()) { - int attrGroupId = attr.getGroupId(); - groups[attrGroupId].push_back(attr); + int groupId = attr.getGroupId(); + int streamType = attr.getStreamType(); + const auto &iter = std::find_if(begin(groups), end(groups), + [groupId, streamType](const auto &iter) { + const auto &frontAttr = iter.second.front(); + return frontAttr.getGroupId() == groupId && frontAttr.getStreamType() == streamType; + }); + // Same Volume Group Id and same stream type + if (iter != end(groups)) { + groups[iter->first].push_back(attr); + } else { + // Add a new Group of AudioAttributes for this product strategy + groups[attrGroupIndex++].push_back(attr); + } } numAttributesGroups = groups.size(); @@ -97,7 +110,7 @@ static jint convertAudioProductStrategiesFromNative( for (const auto &iter : groups) { std::vector<AudioAttributes> audioAttributesGroups = iter.second; jint numAttributes = audioAttributesGroups.size(); - jint jGroupId = iter.first; + jint jGroupId = audioAttributesGroups.front().getGroupId(); jint jLegacyStreamType = audioAttributesGroups.front().getStreamType(); jStatus = JNIAudioAttributeHelper::getJavaArray(env, &jAudioAttributes, numAttributes); diff --git a/core/proto/android/app/enums.proto b/core/proto/android/app/enums.proto index 42437d5b44a0..563ef145b79c 100644 --- a/core/proto/android/app/enums.proto +++ b/core/proto/android/app/enums.proto @@ -203,9 +203,7 @@ enum AppOpEnum { APP_OP_INTERACT_ACROSS_PROFILES = 93; APP_OP_ACTIVATE_PLATFORM_VPN = 94; APP_OP_LOADER_USAGE_STATS = 95; - APP_OP_ACCESS_CALL_AUDIO = 96; + APP_OP_DEPRECATED_1 = 96 [deprecated = true]; APP_OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED = 97; APP_OP_AUTO_REVOKE_MANAGED_BY_INSTALLER = 98; } - - diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto index a3313b21131d..d09273cdd369 100644 --- a/core/proto/android/providers/settings/secure.proto +++ b/core/proto/android/providers/settings/secure.proto @@ -77,7 +77,7 @@ message SecureSettingsProto { optional SettingProto interactive_ui_timeout_ms = 33 [ (android.privacy).dest = DEST_AUTOMATIC ]; // Settings for magnification mode optional SettingProto accessibility_magnification_mode = 34 [ (android.privacy).dest = DEST_AUTOMATIC ]; - optional SettingProto button_long_press_targets = 35 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto button_targets = 35 [ (android.privacy).dest = DEST_AUTOMATIC ]; } optional Accessibility accessibility = 2; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 84d9ce288069..eae614546dfb 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1213,15 +1213,6 @@ android:description="@string/permdesc_acceptHandovers" android:protectionLevel="dangerous" /> - <!-- Allows an application assigned to the Dialer role to be granted access to the telephony - call audio streams, both TX and RX. - <p>Protection level: signature|appop - --> - <permission android:name="android.permission.ACCESS_CALL_AUDIO" - android.label="@string/permlab_accessCallAudio" - android:description="@string/permdesc_accessCallAudio" - android:protectionLevel="signature|appop" /> - <!-- ====================================================================== --> <!-- Permissions for accessing the device microphone --> <!-- ====================================================================== --> @@ -3654,6 +3645,16 @@ <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES" android:protectionLevel="signature|privileged" /> + <!-- Allows an application to use the package installer v2 APIs. + <p>The package installer v2 APIs are still a work in progress and we're + currently validating they work in all scenarios. + <p>Not for use by third-party applications. + TODO(b/152310230): remove this permission once the APIs are confirmed to be sufficient. + @hide + --> + <permission android:name="com.android.permission.USE_INSTALLER_V2" + android:protectionLevel="signature|verifier" /> + <!-- @SystemApi @TestApi Allows an application to clear user data. <p>Not for use by third-party applications @hide diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 28eb98b07690..2a41542d38e4 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1827,6 +1827,9 @@ <attr name="gwpAsanMode" /> + <!-- @hide no longer used, kept to preserve padding --> + <attr name="allowAutoRevokePermissionsExemption" format="boolean" /> + <attr name="autoRevokePermissions"> <enum name="allowed" value="0" /> <enum name="discouraged" value="1" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e3a73377e365..28dcc2fdb573 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4424,4 +4424,7 @@ <!-- Set to true to enable the user switcher on the keyguard. --> <bool name="config_keyguardUserSwitcher">false</bool> + <!-- Set to true to make assistant show in front of the dream/screensaver. --> + <bool name="config_assistantOnTopOfDream">false</bool> + </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index e694e160009e..738688b36257 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -3014,6 +3014,8 @@ <!-- @hide @SystemApi --> <public name="minExtensionVersion" /> <public name="allowNativeHeapPointerTagging" /> + <!-- @hide no longer used, kept to preserve padding --> + <public name="allowAutoRevokePermissionsExemption"/> <public name="autoRevokePermissions" /> <public name="preserveLegacyExternalStorage" /> <public name="mimeGroup" /> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 06f776013233..5b880365657c 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -5482,11 +5482,6 @@ <!-- Error message. This text lets the user know that their current personal apps can't open this specific content. [CHAR LIMIT=NONE] --> <string name="resolver_no_personal_apps_available_resolve">No personal apps can open this content</string> - <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] --> - <string name="permlab_accessCallAudio">Record or play audio in telephony calls</string> - <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR LIMIT=NONE] --> - <string name="permdesc_accessCallAudio">Allows this app, when assigned as default dialer application, to record or play audio in telephony calls.</string> - <!-- Icc depersonalization related strings --> <!-- Label text for PIN entry widget on SIM Network Depersonalization panel [CHAR LIMIT=none] --> <string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY">SIM network unlock PIN</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 22caf4c2a37d..646ffabedb8d 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3953,4 +3953,7 @@ <!-- Set to true to enable the user switcher on the keyguard. --> <java-symbol type="bool" name="config_keyguardUserSwitcher" /> + + <!-- Set to true to make assistant show in front of the dream/screensaver. --> + <java-symbol type="bool" name="config_assistantOnTopOfDream"/> </resources> diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java index 79b803a0cda6..0cd0643ee8c0 100644 --- a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java +++ b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java @@ -25,13 +25,13 @@ import android.app.Service; import android.content.Context; import android.content.Intent; import android.graphics.Color; +import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.util.Log; -import android.util.Size; import android.view.Display; import android.view.Gravity; import android.view.View; @@ -119,15 +119,15 @@ public class TestService extends Service { @Override public void showApplicationOverlay() throws RemoteException { final WindowManager wm = mOverlayContext.getSystemService(WindowManager.class); - final Size size = wm.getCurrentWindowMetrics().getSize(); + final Rect bounds = wm.getCurrentWindowMetrics().getBounds(); final WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams( TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); - wmlp.width = size.getWidth() / 2; - wmlp.height = size.getHeight() / 2; + wmlp.width = bounds.width() / 2; + wmlp.height = bounds.height() / 2; wmlp.gravity = Gravity.CENTER | Gravity.LEFT; wmlp.setTitle(TAG); diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java index 57e5dd8f8f20..f48e66681cc7 100644 --- a/core/tests/coretests/src/android/content/ContentResolverTest.java +++ b/core/tests/coretests/src/android/content/ContentResolverTest.java @@ -238,12 +238,9 @@ public class ContentResolverTest { @Test public void testGetType_providerException() { - try { - mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote/error")); - fail("Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // Expected - } + String type = + mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote/error")); + assertThat(type).isNull(); } @Test @@ -253,4 +250,15 @@ public class ContentResolverTest { assertThat(canonical).isEqualTo( Uri.parse("content://android.content.FakeProviderRemote/canonical")); } + + @Test + public void testCanonicalize_providerException() { + try { + mResolver.canonicalize( + Uri.parse("content://android.content.FakeProviderRemote/error")); + fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // Expected + } + } } diff --git a/core/tests/coretests/src/android/content/FakeProviderRemote.java b/core/tests/coretests/src/android/content/FakeProviderRemote.java index a32009493094..8bc56607f555 100644 --- a/core/tests/coretests/src/android/content/FakeProviderRemote.java +++ b/core/tests/coretests/src/android/content/FakeProviderRemote.java @@ -60,6 +60,9 @@ public class FakeProviderRemote extends ContentProvider { @Override public Uri canonicalize(Uri uri) { + if (uri.getPath() != null && uri.getPath().contains("error")) { + throw new IllegalArgumentException("Expected exception"); + } return new Uri.Builder().scheme(uri.getScheme()).authority(uri.getAuthority()) .appendPath("canonical").build(); } diff --git a/core/tests/coretests/src/android/util/GridScenario.java b/core/tests/coretests/src/android/util/GridScenario.java index 4809a213ab48..e7ee1cd59c7c 100644 --- a/core/tests/coretests/src/android/util/GridScenario.java +++ b/core/tests/coretests/src/android/util/GridScenario.java @@ -233,7 +233,7 @@ public abstract class GridScenario extends Activity { // turn off title bar requestWindowFeature(Window.FEATURE_NO_TITLE); - mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight(); + mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height(); final Params params = new Params(); init(params); diff --git a/core/tests/coretests/src/android/util/ListScenario.java b/core/tests/coretests/src/android/util/ListScenario.java index d4e5a438d855..74dc4b4b34a1 100644 --- a/core/tests/coretests/src/android/util/ListScenario.java +++ b/core/tests/coretests/src/android/util/ListScenario.java @@ -306,7 +306,7 @@ public abstract class ListScenario extends Activity { requestWindowFeature(Window.FEATURE_NO_TITLE); - mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight(); + mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height(); final Params params = createParams(); init(params); diff --git a/core/tests/coretests/src/android/util/ScrollViewScenario.java b/core/tests/coretests/src/android/util/ScrollViewScenario.java index 2c0aa7362dfa..ab1a642a9327 100644 --- a/core/tests/coretests/src/android/util/ScrollViewScenario.java +++ b/core/tests/coretests/src/android/util/ScrollViewScenario.java @@ -239,7 +239,7 @@ public abstract class ScrollViewScenario extends Activity { // for test stability, turn off title bar requestWindowFeature(Window.FEATURE_NO_TITLE); - int screenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight() + int screenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height() - 25; mLinearLayout = new LinearLayout(this); mLinearLayout.setOrientation(LinearLayout.VERTICAL); diff --git a/core/tests/coretests/src/android/view/BigCache.java b/core/tests/coretests/src/android/view/BigCache.java index e465a859218a..3038e79abd72 100644 --- a/core/tests/coretests/src/android/view/BigCache.java +++ b/core/tests/coretests/src/android/view/BigCache.java @@ -17,8 +17,8 @@ package android.view; import android.app.Activity; +import android.graphics.Rect; import android.os.Bundle; -import android.util.Size; import android.widget.LinearLayout; import android.widget.ScrollView; @@ -39,9 +39,9 @@ public class BigCache extends Activity { ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); final int cacheSize = ViewConfiguration.getMaximumDrawingCacheSize(); - final Size windowSize = getWindowManager().getCurrentWindowMetrics().getSize(); - final int screenWidth = windowSize.getWidth(); - final int screenHeight = windowSize.getHeight(); + final Rect windowBounds = getWindowManager().getCurrentWindowMetrics().getBounds(); + final int screenWidth = windowBounds.width(); + final int screenHeight = windowBounds.height(); final View tiny = new View(this); tiny.setId(R.id.a); diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java index 039387c85b11..46e55faae8b6 100644 --- a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java +++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java @@ -22,7 +22,7 @@ import static androidx.test.espresso.matcher.ViewMatchers.withId; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import android.util.Size; +import android.graphics.Rect; import android.widget.TextView; import androidx.test.filters.LargeTest; @@ -55,9 +55,9 @@ public class ScaleGestureDetectorTest { // Specify start and end coordinates with respect to the window size. final WindowManager wm = mScaleGestureActivity.getSystemService(WindowManager.class); - final Size windowSize = wm.getCurrentWindowMetrics().getSize(); - final int windowWidth = windowSize.getWidth(); - final int windowHeight = windowSize.getHeight(); + final Rect windowBounds = wm.getCurrentWindowMetrics().getBounds(); + final int windowWidth = windowBounds.width(); + final int windowHeight = windowBounds.height(); // Obtain coordinates to perform pinch and zoom from the center, to 75% of the display. final int centerX = windowWidth / 2; diff --git a/core/tests/coretests/src/android/view/WindowMetricsTest.java b/core/tests/coretests/src/android/view/WindowMetricsTest.java index fa6886075bfd..74524bf6d76f 100644 --- a/core/tests/coretests/src/android/view/WindowMetricsTest.java +++ b/core/tests/coretests/src/android/view/WindowMetricsTest.java @@ -22,10 +22,10 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; import static org.junit.Assert.assertTrue; import android.content.Context; +import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.Handler; import android.platform.test.annotations.Presubmit; -import android.util.Size; import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; @@ -87,10 +87,12 @@ public class WindowMetricsTest { private static void verifyMetricsSanity(WindowMetrics currentMetrics, WindowMetrics maxMetrics) { - Size currentSize = currentMetrics.getSize(); - Size maxSize = maxMetrics.getSize(); + Rect currentBounds = currentMetrics.getBounds(); + Rect maxBounds = maxMetrics.getBounds(); - assertTrue(maxSize.getWidth() >= currentSize.getWidth()); - assertTrue(maxSize.getHeight() >= currentSize.getHeight()); + assertTrue(maxBounds.width() >= currentBounds.width()); + assertTrue(maxBounds.height() >= currentBounds.height()); + assertTrue(maxBounds.left >= 0); + assertTrue(maxBounds.top >= 0); } } diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java index d5825e20163c..4bd9ccd8d4d3 100644 --- a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java +++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java @@ -16,9 +16,9 @@ package android.view.menu; +import android.graphics.Rect; import android.test.ActivityInstrumentationTestCase; import android.util.PollingCheck; -import android.util.Size; import android.view.View; import android.view.WindowManager; import android.widget.espresso.ContextMenuUtils; @@ -81,8 +81,8 @@ public class ContextMenuTest extends ActivityInstrumentationTestCase<ContextMenu */ private int getMinScreenDimension() { final WindowManager windowManager = getActivity().getSystemService(WindowManager.class); - final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize(); - return Math.min(maxWindowSize.getWidth(), maxWindowSize.getHeight()); + final Rect maxWindowBounds = windowManager.getMaximumWindowMetrics().getBounds(); + return Math.min(maxWindowBounds.width(), maxWindowBounds.height()); } /** diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java index 1b5ce8fd4ce5..4bfffd72d835 100644 --- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java +++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java @@ -37,6 +37,7 @@ import static org.junit.Assert.assertTrue; import android.app.Activity; import android.app.Instrumentation; import android.graphics.Rect; +import android.platform.test.annotations.Presubmit; import android.text.Layout; import android.text.Spannable; import android.text.SpannableString; @@ -48,7 +49,7 @@ import android.view.MotionEvent; import android.view.View; import androidx.test.InstrumentationRegistry; -import androidx.test.filters.SmallTest; +import androidx.test.filters.MediumTest; import androidx.test.filters.Suppress; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.AndroidJUnit4; @@ -67,7 +68,8 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicLong; @RunWith(AndroidJUnit4.class) -@SmallTest +@MediumTest +@Presubmit public class EditorCursorDragTest { private static final String LOG_TAG = EditorCursorDragTest.class.getSimpleName(); @@ -492,6 +494,7 @@ public class EditorCursorDragTest { simulateDrag(tv, events, true); } + @Suppress // b/152574363 @Test public void testLineChangeSlop() throws Throwable { TextView tv = mActivity.findViewById(R.id.textview); diff --git a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java index 3dc001d68a02..ec75e40f1334 100644 --- a/core/tests/coretests/src/android/widget/EditorTouchStateTest.java +++ b/core/tests/coretests/src/android/widget/EditorTouchStateTest.java @@ -22,6 +22,7 @@ import static junit.framework.Assert.assertTrue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; +import android.platform.test.annotations.Presubmit; import android.view.InputDevice; import android.view.MotionEvent; import android.view.ViewConfiguration; @@ -36,6 +37,7 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) @SmallTest +@Presubmit public class EditorTouchStateTest { private EditorTouchState mTouchState; diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java index 8e90a824c873..d51cc328e4fb 100644 --- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java +++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java @@ -111,7 +111,7 @@ public class ListOfInternalSelectionViews extends Activity { protected void onCreate(Bundle icicle) { super.onCreate(icicle); - mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight(); + mScreenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height(); Bundle extras = getIntent().getExtras(); if (extras != null) { diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java index fd1dbfc63708..5cedd13533e7 100644 --- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java +++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java @@ -106,8 +106,8 @@ public class GridTouchVerticalSpacingStackFromBottomTest extends ActivityInstrum int firstTop = firstChild.getTop(); - int windowHeight = mActivity.getWindowManager().getCurrentWindowMetrics().getSize() - .getHeight(); + int windowHeight = mActivity.getWindowManager().getCurrentWindowMetrics().getBounds() + .height(); int distance = TouchUtils.dragViewBy(this, firstChild, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, (int) (windowHeight * 0.75f)); diff --git a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java index e6195b147045..5cca766e1b1e 100644 --- a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java +++ b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java @@ -66,7 +66,7 @@ public class AdjacentListsWithAdjacentISVsInside extends Activity { super.onCreate(savedInstanceState); final int desiredHeight = - (int) (0.8 * getWindowManager().getCurrentWindowMetrics().getSize().getHeight()); + (int) (0.8 * getWindowManager().getCurrentWindowMetrics().getBounds().height()); mLeftListView = new ListView(this); mLeftListView.setAdapter(new AdjacentISVAdapter(desiredHeight)); diff --git a/media/java/android/media/audiopolicy/AudioProductStrategy.java b/media/java/android/media/audiopolicy/AudioProductStrategy.java index f9dbc50e20cf..090f78e4e4f7 100644 --- a/media/java/android/media/audiopolicy/AudioProductStrategy.java +++ b/media/java/android/media/audiopolicy/AudioProductStrategy.java @@ -374,8 +374,8 @@ public final class AudioProductStrategy implements Parcelable { if (refAttr.equals(sDefaultAttributes)) { return false; } - return ((refAttr.getUsage() == AudioAttributes.USAGE_UNKNOWN) - || (attr.getUsage() == refAttr.getUsage())) + return ((refAttr.getSystemUsage() == AudioAttributes.USAGE_UNKNOWN) + || (attr.getSystemUsage() == refAttr.getSystemUsage())) && ((refAttr.getContentType() == AudioAttributes.CONTENT_TYPE_UNKNOWN) || (attr.getContentType() == refAttr.getContentType())) && ((refAttr.getAllFlags() == 0) diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java index 25220951dd7b..daeb731ad457 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java @@ -2210,14 +2210,14 @@ public class CameraTestUtils extends Assert { } public static Size getPreviewSizeBound(WindowManager windowManager, Size bound) { - Size windowSize = windowManager.getCurrentWindowMetrics().getSize(); + Rect windowBounds = windowManager.getCurrentWindowMetrics().getBounds(); - int width = windowSize.getWidth(); - int height = windowSize.getHeight(); + int width = windowBounds.width(); + int height = windowBounds.height(); if (height > width) { height = width; - width = windowSize.getHeight(); + width = windowBounds.height(); } if (bound.getWidth() <= width && diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java index d4eb2a9c75d0..a2da23e918d2 100644 --- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java +++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java @@ -28,11 +28,11 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.IBinder; import android.os.Message; -import android.util.Size; import android.util.Slog; import android.view.Display; import android.view.ViewGroup; @@ -134,8 +134,8 @@ public class FakeApp extends Application { } lp.width = ViewGroup.LayoutParams.MATCH_PARENT; lp.height = ViewGroup.LayoutParams.MATCH_PARENT; - Size maxWindowSize = wm.getMaximumWindowMetrics().getSize(); - int maxSize = Math.max(maxWindowSize.getWidth(), maxWindowSize.getHeight()); + Rect maxWindowBounds = wm.getMaximumWindowMetrics().getBounds(); + int maxSize = Math.max(maxWindowBounds.width(), maxWindowBounds.height()); maxSize *= 2; lp.x = maxSize; lp.y = maxSize; diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java index df00eee63b50..e2120f80f1c9 100644 --- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java +++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java @@ -19,22 +19,22 @@ package com.android.fakeoemfeatures; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; -import java.util.ArrayList; -import java.util.Random; - import android.app.Dialog; import android.app.Service; import android.content.Context; import android.content.Intent; +import android.graphics.Rect; import android.hardware.display.DisplayManager; import android.os.Handler; import android.os.IBinder; import android.os.Message; -import android.util.Size; import android.view.Display; import android.view.ViewGroup; import android.view.WindowManager; +import java.util.ArrayList; +import java.util.Random; + public class FakeBackgroundService extends Service { final ArrayList<int[]> mAllocs = new ArrayList<int[]>(); @@ -99,8 +99,8 @@ public class FakeBackgroundService extends Service { // Create an instance of WindowManager that is adjusted to the area of the display dedicated // for windows with type TYPE_APPLICATION_OVERLAY. final WindowManager wm = windowContext.getSystemService(WindowManager.class); - Size maxWindowSize = wm.getMaximumWindowMetrics().getSize(); - int maxSize = Math.max(maxWindowSize.getWidth(), maxWindowSize.getHeight()); + Rect maxWindowBounds = wm.getMaximumWindowMetrics().getBounds(); + int maxSize = Math.max(maxWindowBounds.width(), maxWindowBounds.height()); maxSize *= 2; lp.x = maxSize; lp.y = maxSize; diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 922caeb0a817..df0de68b1fb9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -69,9 +69,9 @@ public class LocalMediaManager implements BluetoothCallback { private MediaDevice mOnTransferBluetoothDevice; @VisibleForTesting - List<MediaDevice> mMediaDevices = new ArrayList<>(); + List<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>(); @VisibleForTesting - List<MediaDevice> mDisconnectedMediaDevices = new ArrayList<>(); + List<MediaDevice> mDisconnectedMediaDevices = new CopyOnWriteArrayList<>(); @VisibleForTesting MediaDevice mPhoneDevice; @VisibleForTesting @@ -207,6 +207,7 @@ public class LocalMediaManager implements BluetoothCallback { public void stopScan() { mInfoMediaManager.unregisterCallback(mMediaDeviceCallback); mInfoMediaManager.stopScan(); + unRegisterDeviceAttributeChangeCallback(); } /** @@ -397,32 +398,34 @@ public class LocalMediaManager implements BluetoothCallback { } private List<MediaDevice> buildDisconnectedBluetoothDevice() { - for (MediaDevice device : mDisconnectedMediaDevices) { - ((BluetoothMediaDevice) device).getCachedDevice() - .unregisterCallback(mDeviceAttributeChangeCallback); - } - mDisconnectedMediaDevices.clear(); final List<BluetoothDevice> bluetoothDevices = mBluetoothAdapter.getMostRecentlyConnectedDevices(); final CachedBluetoothDeviceManager cachedDeviceManager = mLocalBluetoothManager.getCachedDeviceManager(); + final List<CachedBluetoothDevice> cachedBluetoothDeviceList = new ArrayList<>(); for (BluetoothDevice device : bluetoothDevices) { final CachedBluetoothDevice cachedDevice = cachedDeviceManager.findDevice(device); if (cachedDevice != null) { if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected()) { - final MediaDevice mediaDevice = new BluetoothMediaDevice(mContext, - cachedDevice, - null, null, mPackageName); - if (!mMediaDevices.contains(mediaDevice)) { - cachedDevice.registerCallback(mDeviceAttributeChangeCallback); - mDisconnectedMediaDevices.add(mediaDevice); - } + cachedBluetoothDeviceList.add(cachedDevice); } } } + + unRegisterDeviceAttributeChangeCallback(); + mDisconnectedMediaDevices.clear(); + for (CachedBluetoothDevice cachedDevice : cachedBluetoothDeviceList) { + final MediaDevice mediaDevice = new BluetoothMediaDevice(mContext, + cachedDevice, + null, null, mPackageName); + if (!mMediaDevices.contains(mediaDevice)) { + cachedDevice.registerCallback(mDeviceAttributeChangeCallback); + mDisconnectedMediaDevices.add(mediaDevice); + } + } return new ArrayList<>(mDisconnectedMediaDevices); } @@ -473,6 +476,12 @@ public class LocalMediaManager implements BluetoothCallback { } } + private void unRegisterDeviceAttributeChangeCallback() { + for (MediaDevice device : mDisconnectedMediaDevices) { + ((BluetoothMediaDevice) device).getCachedDevice() + .unregisterCallback(mDeviceAttributeChangeCallback); + } + } /** * Callback for notifying device information updating diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 8bf48e59165e..c713d7813a54 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -17,6 +17,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import android.content.Context; import android.content.Intent; import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; @@ -36,7 +37,10 @@ import com.android.settingslib.R; import java.util.List; -public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { +/** + * Track status of Wi-Fi for the Sys UI. + */ +public class WifiStatusTracker { private final Context mContext; private final WifiNetworkScoreCache mWifiNetworkScoreCache; private final WifiManager mWifiManager; @@ -55,8 +59,9 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { .clearCapabilities() .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI).build(); - private final ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager - .NetworkCallback() { + private final NetworkCallback mNetworkCallback = new NetworkCallback() { + // Note: onCapabilitiesChanged is guaranteed to be called "immediately" after onAvailable + // and onLinkPropertiesChanged. @Override public void onCapabilitiesChanged( Network network, NetworkCapabilities networkCapabilities) { @@ -64,11 +69,35 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { mCallback.run(); } }; + private final NetworkCallback mDefaultNetworkCallback = new NetworkCallback() { + @Override + public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) { + // network is now the default network, and its capabilities are nc. + // This method will always be called immediately after the network becomes the + // default, in addition to any time the capabilities change while the network is + // the default. + mDefaultNetwork = network; + mDefaultNetworkCapabilities = nc; + updateStatusLabel(); + mCallback.run(); + } + @Override + public void onLost(Network network) { + // The system no longer has a default network. + mDefaultNetwork = null; + mDefaultNetworkCapabilities = null; + updateStatusLabel(); + mCallback.run(); + } + }; + private Network mDefaultNetwork = null; + private NetworkCapabilities mDefaultNetworkCapabilities = null; private final Runnable mCallback; private WifiInfo mWifiInfo; public boolean enabled; public boolean isCaptivePortal; + public boolean isDefaultNetwork; public int state; public boolean connected; public String ssid; @@ -94,11 +123,13 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { mWifiNetworkScoreCache.registerListener(mCacheListener); mConnectivityManager.registerNetworkCallback( mNetworkRequest, mNetworkCallback, mHandler); + mConnectivityManager.registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler); } else { mNetworkScoreManager.unregisterNetworkScoreCache(NetworkKey.TYPE_WIFI, mWifiNetworkScoreCache); mWifiNetworkScoreCache.unregisterListener(); mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); + mConnectivityManager.unregisterNetworkCallback(mDefaultNetworkCallback); } } @@ -154,8 +185,17 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { } private void updateStatusLabel() { - final NetworkCapabilities networkCapabilities - = mConnectivityManager.getNetworkCapabilities(mWifiManager.getCurrentNetwork()); + NetworkCapabilities networkCapabilities; + final Network currentWifiNetwork = mWifiManager.getCurrentNetwork(); + if (currentWifiNetwork != null && currentWifiNetwork.equals(mDefaultNetwork)) { + // Wifi is connected and the default network. + isDefaultNetwork = true; + networkCapabilities = mDefaultNetworkCapabilities; + } else { + isDefaultNetwork = false; + networkCapabilities = mConnectivityManager.getNetworkCapabilities( + mWifiManager.getCurrentNetwork()); + } isCaptivePortal = false; if (networkCapabilities != null) { if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) { diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index d320df9c24ba..3c0ddc4b65c5 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -163,6 +163,6 @@ public class SecureSettings { Settings.Secure.AWARE_TAP_PAUSE_TOUCH_COUNT, Settings.Secure.PEOPLE_STRIP, Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, - Settings.Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS, + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, }; } diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index 8801a9c32a36..3e64a378bc6a 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -78,9 +78,7 @@ public class SecureSettingsValidators { ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR); // technically either ComponentName or class name, but there's proper value // validation at callsites, so allow any non-null string - VALIDATORS.put( - Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, - ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR); + VALIDATORS.put(Secure.ACCESSIBILITY_BUTTON_TARGET_COMPONENT, value -> value != null); VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, BOOLEAN_VALIDATOR); @@ -248,7 +246,7 @@ public class SecureSettingsValidators { Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN, Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW)); VALIDATORS.put( - Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS, + Secure.ACCESSIBILITY_BUTTON_TARGETS, ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR); } } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index b22caf0edc66..6fba15f5381f 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1811,8 +1811,8 @@ class SettingsProtoDumpUtil { Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE, SecureSettingsProto.Accessibility.ACCESSIBILITY_MAGNIFICATION_MODE); dumpSetting(s, p, - Settings.Secure.ACCESSIBILITY_BUTTON_LONG_PRESS_TARGETS, - SecureSettingsProto.Accessibility.BUTTON_LONG_PRESS_TARGETS); + Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS, + SecureSettingsProto.Accessibility.BUTTON_TARGETS); p.end(accessibilityToken); final long adaptiveSleepToken = p.start(SecureSettingsProto.ADAPTIVE_SLEEP); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index c7fb00a8130c..4771c4139a5b 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -81,6 +81,8 @@ <uses-permission android:name="android.permission.READ_INPUT_STATE" /> <uses-permission android:name="android.permission.SET_ORIENTATION" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> + <!-- TODO(b/152310230): remove once APIs are confirmed to be sufficient --> + <uses-permission android:name="com.android.permission.USE_INSTALLER_V2" /> <uses-permission android:name="android.permission.MOVE_PACKAGE" /> <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" /> <uses-permission android:name="android.permission.CLEAR_APP_CACHE" /> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 0ae00e1ac8b5..a1376c3203f5 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -1808,13 +1808,13 @@ public class BugreportProgressService extends Service { * Current value of progress (in percentage) of the bugreport generation as * displayed by the UI. */ - AtomicInteger progress; + AtomicInteger progress = new AtomicInteger(0); /** * Last value of progress (in percentage) of the bugreport generation for which * system notification was updated. */ - AtomicInteger lastProgress; + AtomicInteger lastProgress = new AtomicInteger(0); /** * Time of the last progress update. diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml index 7708b8e9db6c..6e1fd2072b32 100644 --- a/packages/SystemUI/res/layout/controls_base_item.xml +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -30,8 +30,8 @@ <ImageView android:id="@+id/icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="@dimen/control_icon_size" + android:layout_height="@dimen/control_icon_size" android:paddingTop="@dimen/control_padding_adjustment" android:clickable="false" android:focusable="false" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 432cd749abbd..ee7f5230145e 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1225,6 +1225,7 @@ <dimen name="controls_top_margin">44dp</dimen> <dimen name="control_header_text_size">22sp</dimen> <dimen name="control_text_size">14sp</dimen> + <dimen name="control_icon_size">24dp</dimen> <dimen name="control_spacing">4dp</dimen> <dimen name="control_list_divider">1dp</dimen> <dimen name="control_corner_radius">12dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index c8c35c704297..8a3a16e9a6cf 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -374,9 +374,31 @@ <string name="biometric_dialog_wrong_password">Wrong password</string> <!-- Error string shown when the user enters too many incorrect attempts [CHAR LIMIT=120]--> <string name="biometric_dialog_credential_too_many_attempts">Too many incorrect attempts.\nTry again in <xliff:g id="number">%d</xliff:g> seconds.</string> + <!-- Error string shown when the user enters an incorrect PIN/pattern/password and it counts towards the max attempts before the data on the device is wiped. [CHAR LIMIT=NONE]--> <string name="biometric_dialog_credential_attempts_before_wipe">Try again. Attempt <xliff:g id="attempts" example="1">%1$d</xliff:g> of <xliff:g id="max_attempts" example="3">%2$d</xliff:g>.</string> + <!-- Title of a dialog shown when the user only has one attempt left to provide the correct PIN/pattern/password before the device, one of its users, or a work profile is wiped. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_attempt_before_wipe_dialog_title">Your data will be deleted</string> + <!-- Content of a dialog shown when the user only has one attempt left to provide the correct lock pattern before the device is wiped. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_pattern_attempt_before_wipe_device">If you enter an incorrect pattern on the next attempt, this device\u2019s data will be deleted.</string> + <!-- Content of a dialog shown when the user only has one attempt left to provide the correct PIN before the device is wiped. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_pin_attempt_before_wipe_device">If you enter an incorrect PIN on the next attempt, this device\u2019s data will be deleted.</string> + <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the device is wiped. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_password_attempt_before_wipe_device">If you enter an incorrect password on the next attempt, this device\u2019s data will be deleted.</string> + <!-- Content of a dialog shown when the user only has one attempt left to provide the correct lock pattern before the user is removed. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_pattern_attempt_before_wipe_user">If you enter an incorrect pattern on the next attempt, this user will be deleted.</string> + <!-- Content of a dialog shown when the user only has one attempt left to provide the correct PIN before the user is removed. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_pin_attempt_before_wipe_user">If you enter an incorrect PIN on the next attempt, this user will be deleted.</string> + <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the user is removed. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_password_attempt_before_wipe_user">If you enter an incorrect password on the next attempt, this user will be deleted.</string> + <!-- Content of a dialog shown when the user only has one attempt left to provide the correct pattern before the work profile is removed. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_pattern_attempt_before_wipe_profile">If you enter an incorrect pattern on the next attempt, your work profile and its data will be deleted.</string> + <!-- Content of a dialog shown when the user only has one attempt left to provide the correct PIN before the work profile is removed. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_pin_attempt_before_wipe_profile">If you enter an incorrect PIN on the next attempt, your work profile and its data will be deleted.</string> + <!-- Content of a dialog shown when the user only has one attempt left to provide the correct password before the work profile is removed. [CHAR LIMIT=NONE] --> + <string name="biometric_dialog_last_password_attempt_before_wipe_profile">If you enter an incorrect password on the next attempt, your work profile and its data will be deleted.</string> + <!-- Content of a dialog shown when the user has failed to provide the device lock too many times and the device is wiped. [CHAR LIMIT=NONE] --> <string name="biometric_dialog_failed_attempts_now_wiping_device">Too many incorrect attempts. This device\u2019s data will be deleted.</string> <!-- Content of a dialog shown when the user has failed to provide the user lock too many times and the user is removed. [CHAR LIMIT=NONE] --> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index 49e3e5724988..3bda3c8df699 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -20,9 +20,7 @@ import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -38,7 +36,6 @@ import android.app.ActivityTaskManager; import android.app.AppGlobals; import android.app.IAssistDataReceiver; import android.app.WindowConfiguration; -import android.app.WindowConfiguration.ActivityType; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -113,15 +110,18 @@ public class ActivityManagerWrapper { * @return the top running task (can be {@code null}). */ public ActivityManager.RunningTaskInfo getRunningTask() { - return getRunningTask(ACTIVITY_TYPE_RECENTS /* ignoreActivityType */); + return getRunningTask(false /* filterVisibleRecents */); } - public ActivityManager.RunningTaskInfo getRunningTask(@ActivityType int ignoreActivityType) { + /** + * @return the top running task filtering only for tasks that can be visible in the recent tasks + * list (can be {@code null}). + */ + public ActivityManager.RunningTaskInfo getRunningTask(boolean filterOnlyVisibleRecents) { // Note: The set of running tasks from the system is ordered by recency try { List<ActivityManager.RunningTaskInfo> tasks = - ActivityTaskManager.getService().getFilteredTasks(1, ignoreActivityType, - WINDOWING_MODE_PINNED /* ignoreWindowingMode */); + ActivityTaskManager.getService().getFilteredTasks(1, filterOnlyVisibleRecents); if (tasks.isEmpty()) { return null; } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 3afe19f926ec..7cbc840afed4 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -127,6 +127,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private static final boolean DEBUG = KeyguardConstants.DEBUG; private static final boolean DEBUG_SIM_STATES = KeyguardConstants.DEBUG_SIM_STATES; private static final boolean DEBUG_FACE = true; + private static final boolean DEBUG_SPEW = false; private static final int LOW_BATTERY_THRESHOLD = 20; private static final String ACTION_FACE_UNLOCK_STARTED @@ -324,7 +325,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab } }; - private class BiometricAuthenticated { + @VisibleForTesting + static class BiometricAuthenticated { private final boolean mAuthenticated; private final boolean mIsStrongBiometric; @@ -338,11 +340,14 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private SparseBooleanArray mUserHasTrust = new SparseBooleanArray(); private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray(); private SparseBooleanArray mUserTrustIsUsuallyManaged = new SparseBooleanArray(); - private SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>(); - private SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>(); private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray(); private Map<Integer, Intent> mSecondaryLockscreenRequirement = new HashMap<Integer, Intent>(); + @VisibleForTesting + SparseArray<BiometricAuthenticated> mUserFingerprintAuthenticated = new SparseArray<>(); + @VisibleForTesting + SparseArray<BiometricAuthenticated> mUserFaceAuthenticated = new SparseArray<>(); + private static int sCurrentUser; private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState; @@ -1850,11 +1855,33 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab // Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an // instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware. - return (mBouncer || mAuthInterruptActive || awakeKeyguard || shouldListenForFaceAssistant()) + final boolean shouldListen = + (mBouncer || mAuthInterruptActive || awakeKeyguard + || shouldListenForFaceAssistant()) && !mSwitchingUser && !isFaceDisabled(user) && becauseCannotSkipBouncer && !mKeyguardGoingAway && mFaceSettingEnabledForUser.get(user) && !mLockIconPressed && strongAuthAllowsScanning && mIsPrimaryUser && !mSecureCameraLaunched; + + // Too chatty, but very useful when debugging issues. + if (DEBUG_SPEW) { + Log.v(TAG, "shouldListenForFace(" + user + ")=" + shouldListen + "... " + + ", mBouncer: " + mBouncer + + ", mAuthInterruptActive: " + mAuthInterruptActive + + ", awakeKeyguard: " + awakeKeyguard + + ", shouldListenForFaceAssistant: " + shouldListenForFaceAssistant() + + ", mSwitchingUser: " + mSwitchingUser + + ", isFaceDisabled(" + user + "): " + isFaceDisabled(user) + + ", becauseCannotSkipBouncer: " + becauseCannotSkipBouncer + + ", mKeyguardGoingAway: " + mKeyguardGoingAway + + ", mFaceSettingEnabledForUser(" + user + "): " + + mFaceSettingEnabledForUser.get(user) + + ", mLockIconPressed: " + mLockIconPressed + + ", strongAuthAllowsScanning: " + strongAuthAllowsScanning + + ", isPrimaryUser: " + mIsPrimaryUser + + ", mSecureCameraLaunched: " + mSecureCameraLaunched); + } + return shouldListen; } /** @@ -2049,8 +2076,10 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab /** * Handle {@link #MSG_USER_SWITCHING} */ - private void handleUserSwitching(int userId, IRemoteCallback reply) { + @VisibleForTesting + void handleUserSwitching(int userId, IRemoteCallback reply) { Assert.isMainThread(); + clearBiometricRecognized(); mUserTrustIsUsuallyManaged.put(userId, mTrustManager.isTrustUsuallyManaged(userId)); for (int i = 0; i < mCallbacks.size(); i++) { KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get(); diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java index 13f3c0fce5c2..b006bc1351a3 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java @@ -347,21 +347,35 @@ public abstract class AuthCredentialView extends LinearLayout { showError(message); } - // Only show popup dialog before wipe. + // Only show dialog if <=1 attempts are left before wiping. final int remainingAttempts = maxAttempts - numAttempts; - if (remainingAttempts <= 0) { - showNowWipingMessage(); - mContainerView.animateAway(AuthDialogCallback.DISMISSED_ERROR); + if (remainingAttempts == 1) { + showLastAttemptBeforeWipeDialog(); + } else if (remainingAttempts <= 0) { + showNowWipingDialog(); } return true; } - private void showNowWipingMessage() { + private void showLastAttemptBeforeWipeDialog() { + final AlertDialog alertDialog = new AlertDialog.Builder(mContext) + .setTitle(R.string.biometric_dialog_last_attempt_before_wipe_dialog_title) + .setMessage( + getLastAttemptBeforeWipeMessageRes(getUserTypeForWipe(), mCredentialType)) + .setPositiveButton(android.R.string.ok, null) + .create(); + alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL); + alertDialog.show(); + } + + private void showNowWipingDialog() { final AlertDialog alertDialog = new AlertDialog.Builder(mContext) .setMessage(getNowWipingMessageRes(getUserTypeForWipe())) .setPositiveButton(R.string.biometric_dialog_now_wiping_dialog_dismiss, null) + .setOnDismissListener( + dialog -> mContainerView.animateAway(AuthDialogCallback.DISMISSED_ERROR)) .create(); - alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL); alertDialog.show(); } @@ -377,6 +391,59 @@ public abstract class AuthCredentialView extends LinearLayout { } } + private static @StringRes int getLastAttemptBeforeWipeMessageRes( + @UserType int userType, @Utils.CredentialType int credentialType) { + switch (userType) { + case USER_TYPE_PRIMARY: + return getLastAttemptBeforeWipeDeviceMessageRes(credentialType); + case USER_TYPE_MANAGED_PROFILE: + return getLastAttemptBeforeWipeProfileMessageRes(credentialType); + case USER_TYPE_SECONDARY: + return getLastAttemptBeforeWipeUserMessageRes(credentialType); + default: + throw new IllegalArgumentException("Unrecognized user type:" + userType); + } + } + + private static @StringRes int getLastAttemptBeforeWipeDeviceMessageRes( + @Utils.CredentialType int credentialType) { + switch (credentialType) { + case Utils.CREDENTIAL_PIN: + return R.string.biometric_dialog_last_pin_attempt_before_wipe_device; + case Utils.CREDENTIAL_PATTERN: + return R.string.biometric_dialog_last_pattern_attempt_before_wipe_device; + case Utils.CREDENTIAL_PASSWORD: + default: + return R.string.biometric_dialog_last_password_attempt_before_wipe_device; + } + } + + private static @StringRes int getLastAttemptBeforeWipeProfileMessageRes( + @Utils.CredentialType int credentialType) { + switch (credentialType) { + case Utils.CREDENTIAL_PIN: + return R.string.biometric_dialog_last_pin_attempt_before_wipe_profile; + case Utils.CREDENTIAL_PATTERN: + return R.string.biometric_dialog_last_pattern_attempt_before_wipe_profile; + case Utils.CREDENTIAL_PASSWORD: + default: + return R.string.biometric_dialog_last_password_attempt_before_wipe_profile; + } + } + + private static @StringRes int getLastAttemptBeforeWipeUserMessageRes( + @Utils.CredentialType int credentialType) { + switch (credentialType) { + case Utils.CREDENTIAL_PIN: + return R.string.biometric_dialog_last_pin_attempt_before_wipe_user; + case Utils.CREDENTIAL_PATTERN: + return R.string.biometric_dialog_last_pattern_attempt_before_wipe_user; + case Utils.CREDENTIAL_PASSWORD: + default: + return R.string.biometric_dialog_last_password_attempt_before_wipe_user; + } + } + private static @StringRes int getNowWipingMessageRes(@UserType int userType) { switch (userType) { case USER_TYPE_PRIMARY: diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt index 6c49c82acdc0..118fcbb20f26 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt @@ -252,10 +252,17 @@ class ControlsControllerImpl @Inject constructor ( it.controlId in favoritesForComponentKeys ) } + val removedControls = mutableListOf<ControlStatus>() + Favorites.getStructuresForComponent(componentName).forEach { st -> + st.controls.forEach { + if (it.controlId in removed) { + val r = createRemovedStatus(componentName, it, st.structure) + removedControls.add(r) + } + } + } val loadData = createLoadDataObject( - Favorites.getControlsForComponent(componentName) - .filter { it.controlId in removed } - .map { createRemovedStatus(componentName, it) } + + removedControls + controlsWithFavorite, favoritesForComponentKeys ) @@ -266,17 +273,15 @@ class ControlsControllerImpl @Inject constructor ( override fun error(message: String) { loadCanceller = null executor.execute { - val loadData = Favorites.getControlsForComponent(componentName) - .let { controls -> - val keys = controls.map { it.controlId } - createLoadDataObject( - controls.map { - createRemovedStatus(componentName, it, false) - }, - keys, - true - ) - } + val controls = Favorites.getStructuresForComponent(componentName) + .flatMap { st -> + st.controls.map { + createRemovedStatus(componentName, it, st.structure, + false) + } + } + val keys = controls.map { it.control.controlId } + val loadData = createLoadDataObject(controls, keys, true) dataCallback.accept(loadData) } } @@ -372,6 +377,7 @@ class ControlsControllerImpl @Inject constructor ( private fun createRemovedStatus( componentName: ComponentName, controlInfo: ControlInfo, + structure: CharSequence, setRemoved: Boolean = true ): ControlStatus { val intent = Intent(Intent.ACTION_MAIN).apply { @@ -384,6 +390,8 @@ class ControlsControllerImpl @Inject constructor ( 0) val control = Control.StatelessBuilder(controlInfo.controlId, pendingIntent) .setTitle(controlInfo.controlTitle) + .setSubtitle(controlInfo.controlSubtitle) + .setStructure(structure) .setDeviceType(controlInfo.deviceType) .build() return ControlStatus(control, componentName, true, setRemoved) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt index 15c2a0afe819..a7a41033bb5d 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ChallengeDialogs.kt @@ -34,24 +34,29 @@ import com.android.systemui.R /** * Creates all dialogs for challengeValues that can occur from a call to - * {@link ControlsProviderService#performControlAction}. The types of challenge - * responses are listed in {@link ControlAction.ResponseResult}. + * [ControlsProviderService#performControlAction]. The types of challenge responses are listed in + * [ControlAction.ResponseResult]. */ object ChallengeDialogs { - fun createPinDialog(cvh: ControlViewHolder): Dialog? { + private const val WINDOW_TYPE = WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY + private const val STYLE = android.R.style.Theme_DeviceDefault_Dialog_Alert + + /** + * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_PIN] and + * [ControlAction#RESPONSE_CHALLENGE_PIN] responses, decided by the useAlphaNumeric + * parameter. + */ + fun createPinDialog(cvh: ControlViewHolder, useAlphaNumeric: Boolean): Dialog? { val lastAction = cvh.lastAction if (lastAction == null) { Log.e(ControlsUiController.TAG, "PIN Dialog attempted but no last action is set. Will not show") return null } - val builder = AlertDialog.Builder( - cvh.context, - android.R.style.Theme_DeviceDefault_Dialog_Alert - ).apply { + val builder = AlertDialog.Builder(cvh.context, STYLE).apply { val res = cvh.context.resources - setTitle(res.getString(R.string.controls_pin_verify, *arrayOf(cvh.title.getText()))) + setTitle(res.getString(R.string.controls_pin_verify, cvh.title.getText())) setView(R.layout.controls_dialog_pin) setPositiveButton( android.R.string.ok, @@ -71,25 +76,64 @@ object ChallengeDialogs { } return builder.create().apply { getWindow().apply { - setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) + setType(WINDOW_TYPE) setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) } setOnShowListener(DialogInterface.OnShowListener { _ -> val editText = requireViewById<EditText>(R.id.controls_pin_input) - requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { v -> - if ((v as CheckBox).isChecked) { - editText.setInputType( - InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD) - } else { - editText.setInputType( - InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD) - } + val useAlphaCheckBox = requireViewById<CheckBox>(R.id.controls_pin_use_alpha) + useAlphaCheckBox.setChecked(useAlphaNumeric) + setInputType(editText, useAlphaCheckBox.isChecked()) + requireViewById<CheckBox>(R.id.controls_pin_use_alpha).setOnClickListener { _ -> + setInputType(editText, useAlphaCheckBox.isChecked()) } editText.requestFocus() }) } } + /** + * AlertDialogs to handle [ControlAction#RESPONSE_CHALLENGE_ACK] response type. + */ + fun createConfirmationDialog(cvh: ControlViewHolder): Dialog? { + val lastAction = cvh.lastAction + if (lastAction == null) { + Log.e(ControlsUiController.TAG, + "Confirmation Dialog attempted but no last action is set. Will not show") + return null + } + val builder = AlertDialog.Builder(cvh.context, STYLE).apply { + val res = cvh.context.resources + setMessage(res.getString( + R.string.controls_confirmation_message, cvh.title.getText())) + setPositiveButton( + android.R.string.ok, + DialogInterface.OnClickListener { dialog, _ -> + cvh.action(addChallengeValue(lastAction, "true")) + dialog.dismiss() + }) + setNegativeButton( + android.R.string.cancel, + DialogInterface.OnClickListener { dialog, _ -> dialog.cancel() } + ) + } + return builder.create().apply { + getWindow().apply { + setType(WINDOW_TYPE) + } + } + } + + private fun setInputType(editText: EditText, useTextInput: Boolean) { + if (useTextInput) { + editText.setInputType( + InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD) + } else { + editText.setInputType( + InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD) + } + } + private fun addChallengeValue(action: ControlAction, challengeValue: String): ControlAction { val id = action.getTemplateId() return when (action) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt index 9f5dd02b4514..7d3a86091869 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -21,6 +21,7 @@ import android.graphics.drawable.ClipDrawable import android.graphics.drawable.GradientDrawable import android.graphics.drawable.LayerDrawable import android.service.controls.Control +import android.service.controls.DeviceTypes import android.service.controls.actions.ControlAction import android.service.controls.templates.ControlTemplate import android.service.controls.templates.StatelessTemplate @@ -156,7 +157,11 @@ class ControlViewHolder( statusExtra.setTextColor(fg) icon.setImageDrawable(ri.icon) - icon.setImageTintList(fg) + + // do not color app icons + if (deviceType != DeviceTypes.TYPE_ROUTINE) { + icon.setImageTintList(fg) + } (clipLayer.getDrawable() as GradientDrawable).apply { setColor(context.getResources().getColor(bg, context.getTheme())) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index b0db4370f38d..05a0c45c2e15 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -442,7 +442,15 @@ class ControlsUiControllerImpl @Inject constructor ( controlViewsById.get(key)?.let { cvh -> when (response) { ControlAction.RESPONSE_CHALLENGE_PIN -> { - activeDialog = ChallengeDialogs.createPinDialog(cvh) + activeDialog = ChallengeDialogs.createPinDialog(cvh, false) + activeDialog?.show() + } + ControlAction.RESPONSE_CHALLENGE_PASSPHRASE -> { + activeDialog = ChallengeDialogs.createPinDialog(cvh, true) + activeDialog?.show() + } + ControlAction.RESPONSE_CHALLENGE_ACK -> { + activeDialog = ChallengeDialogs.createConfirmationDialog(cvh) activeDialog?.show() } else -> cvh.actionResponse(response) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt index 27e46497b20a..810ea65c7873 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt @@ -64,7 +64,7 @@ data class RenderInfo( val iconState = deviceIconMap.getValue(iconKey) val resourceId = iconState[enabled] - var icon: Drawable? = null + var icon: Drawable? if (resourceId == APP_ICON_ID) { icon = appIconMap.get(componentName) if (icon == null) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt index c495c58fff2a..f79c8b2393d0 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt @@ -64,12 +64,13 @@ class ToggleRangeBehavior : Behavior { val gestureListener = ToggleRangeGestureListener(cvh.layout) val gestureDetector = GestureDetector(context, gestureListener) - cvh.layout.setOnTouchListener { _: View, e: MotionEvent -> + cvh.layout.setOnTouchListener { v: View, e: MotionEvent -> if (gestureDetector.onTouchEvent(e)) { return@setOnTouchListener true } if (e.getAction() == MotionEvent.ACTION_UP && gestureListener.isDragging) { + v.getParent().requestDisallowInterceptTouchEvent(false) gestureListener.isDragging = false endUpdateRange() return@setOnTouchListener true @@ -254,6 +255,7 @@ class ToggleRangeBehavior : Behavior { yDiff: Float ): Boolean { if (!isDragging) { + v.getParent().requestDisallowInterceptTouchEvent(true) this@ToggleRangeBehavior.beginUpdateRange() isDragging = true } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java index aa6444973a6f..3b3d9dde3b7e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java @@ -17,7 +17,6 @@ package com.android.systemui.recents; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON; import static com.android.systemui.Prefs.Key.DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT; @@ -27,8 +26,7 @@ import static com.android.systemui.Prefs.Key.HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDIN import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_COUNT; import static com.android.systemui.Prefs.Key.OVERVIEW_OPENED_FROM_HOME_COUNT; import static com.android.systemui.shared.system.LauncherEventUtil.DISMISS; -import static com.android.systemui.shared.system.LauncherEventUtil - .RECENTS_QUICK_SCRUB_ONBOARDING_TIP; +import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_QUICK_SCRUB_ONBOARDING_TIP; import static com.android.systemui.shared.system.LauncherEventUtil.RECENTS_SWIPE_UP_ONBOARDING_TIP; import static com.android.systemui.shared.system.LauncherEventUtil.VISIBLE; @@ -139,7 +137,7 @@ public class RecentsOnboarding { private void onAppLaunch() { ActivityManager.RunningTaskInfo info = ActivityManagerWrapper.getInstance() - .getRunningTask(ACTIVITY_TYPE_UNDEFINED /* ignoreActivityType */); + .getRunningTask(); if (info == null) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index adca10ff7677..ecfe1168b7f0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -110,10 +110,14 @@ public class EdgeBackGestureHandler implements DisplayListener, private final float mTouchSlop; // Duration after which we consider the event as longpress. private final int mLongPressTimeout; + // The back gesture type + private int mBackType; private final PointF mDownPoint = new PointF(); + private final PointF mEndPoint = new PointF(); private boolean mThresholdCrossed = false; private boolean mAllowGesture = false; + private boolean mLogGesture = false; private boolean mInRejectedExclusion = false; private boolean mIsOnLeftEdge; @@ -141,24 +145,16 @@ public class EdgeBackGestureHandler implements DisplayListener, mOverviewProxyService.notifyBackAction(true, (int) mDownPoint.x, (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge); - int backtype = (mInRejectedExclusion - ? SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED_REJECTED : - SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED); - SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype, - (int) mDownPoint.y, mIsOnLeftEdge - ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT : - SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT); + logGesture(mInRejectedExclusion + ? SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED_REJECTED + : SysUiStatsLog.BACK_GESTURE__TYPE__COMPLETED); } @Override public void cancelBack() { + logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE); mOverviewProxyService.notifyBackAction(false, (int) mDownPoint.x, (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge); - int backtype = SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE; - SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backtype, - (int) mDownPoint.y, mIsOnLeftEdge - ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT : - SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT); } }; @@ -331,39 +327,55 @@ public class EdgeBackGestureHandler implements DisplayListener, } private boolean isWithinTouchRegion(int x, int y) { - // Disallow if too far from the edge - if (x > mEdgeWidthLeft + mLeftInset - && x < (mDisplaySize.x - mEdgeWidthRight - mRightInset)) { + // Disallow if we are in the bottom gesture area + if (y >= (mDisplaySize.y - mBottomGestureHeight)) { return false; } - // Disallow if we are in the bottom gesture area - if (y >= (mDisplaySize.y - mBottomGestureHeight)) { + // If the point is way too far (twice the margin), it is + // not interesting to us for logging purposes, nor we + // should process it. Simply return false and keep + // mLogGesture = false. + if (x > 2 * (mEdgeWidthLeft + mLeftInset) + && x < (mDisplaySize.x - 2 * (mEdgeWidthRight + mRightInset))) { return false; } + // Denotes whether we should proceed with the gesture. + // Even if it is false, we may want to log it assuming + // it is not invalid due to exclusion. + boolean withinRange = x <= mEdgeWidthLeft + mLeftInset + || x >= (mDisplaySize.x - mEdgeWidthRight - mRightInset); + // Always allow if the user is in a transient sticky immersive state if (mIsNavBarShownTransiently) { - return true; + mLogGesture = true; + return withinRange; } - boolean isInExcludedRegion = mExcludeRegion.contains(x, y); - if (isInExcludedRegion) { - mOverviewProxyService.notifyBackAction(false /* completed */, -1, -1, - false /* isButton */, !mIsOnLeftEdge); - SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, - SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_EXCLUDED, y, - mIsOnLeftEdge ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT : - SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT); - } else { - mInRejectedExclusion = mUnrestrictedExcludeRegion.contains(x, y); + if (mExcludeRegion.contains(x, y)) { + if (withinRange) { + // Log as exclusion only if it is in acceptable range in the first place. + mOverviewProxyService.notifyBackAction( + false /* completed */, -1, -1, false /* isButton */, !mIsOnLeftEdge); + // We don't have the end point for logging purposes. + mEndPoint.x = -1; + mEndPoint.y = -1; + mLogGesture = true; + logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_EXCLUDED); + } + return false; } - return !isInExcludedRegion; + + mInRejectedExclusion = mUnrestrictedExcludeRegion.contains(x, y); + mLogGesture = true; + return withinRange; } private void cancelGesture(MotionEvent ev) { // Send action cancel to reset all the touch events mAllowGesture = false; + mLogGesture = false; mInRejectedExclusion = false; MotionEvent cancelEv = MotionEvent.obtain(ev); cancelEv.setAction(MotionEvent.ACTION_CANCEL); @@ -371,51 +383,86 @@ public class EdgeBackGestureHandler implements DisplayListener, cancelEv.recycle(); } + private void logGesture(int backType) { + if (!mLogGesture) { + return; + } + mLogGesture = false; + SysUiStatsLog.write(SysUiStatsLog.BACK_GESTURE_REPORTED_REPORTED, backType, + (int) mDownPoint.y, mIsOnLeftEdge + ? SysUiStatsLog.BACK_GESTURE__X_LOCATION__LEFT + : SysUiStatsLog.BACK_GESTURE__X_LOCATION__RIGHT, + (int) mDownPoint.x, (int) mDownPoint.y, + (int) mEndPoint.x, (int) mEndPoint.y, + mEdgeWidthLeft + mLeftInset, + mDisplaySize.x - (mEdgeWidthRight + mRightInset)); + } + private void onMotionEvent(MotionEvent ev) { int action = ev.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { // Verify if this is in within the touch region and we aren't in immersive mode, and // either the bouncer is showing or the notification panel is hidden mIsOnLeftEdge = ev.getX() <= mEdgeWidthLeft + mLeftInset; + mLogGesture = false; mInRejectedExclusion = false; mAllowGesture = !QuickStepContract.isBackGestureDisabled(mSysUiFlags) && isWithinTouchRegion((int) ev.getX(), (int) ev.getY()); if (mAllowGesture) { mEdgeBackPlugin.setIsLeftPanel(mIsOnLeftEdge); mEdgeBackPlugin.onMotionEvent(ev); - + } + if (mLogGesture) { mDownPoint.set(ev.getX(), ev.getY()); + mEndPoint.set(-1, -1); mThresholdCrossed = false; } - - } else if (mAllowGesture) { + } else if (mAllowGesture || mLogGesture) { if (!mThresholdCrossed) { + mEndPoint.x = (int) ev.getX(); + mEndPoint.y = (int) ev.getY(); if (action == MotionEvent.ACTION_POINTER_DOWN) { - // We do not support multi touch for back gesture - cancelGesture(ev); + if (mAllowGesture) { + logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_MULTI_TOUCH); + // We do not support multi touch for back gesture + cancelGesture(ev); + } + mLogGesture = false; return; } else if (action == MotionEvent.ACTION_MOVE) { if ((ev.getEventTime() - ev.getDownTime()) > mLongPressTimeout) { - cancelGesture(ev); + if (mAllowGesture) { + logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_LONG_PRESS); + cancelGesture(ev); + } + mLogGesture = false; return; } float dx = Math.abs(ev.getX() - mDownPoint.x); float dy = Math.abs(ev.getY() - mDownPoint.y); if (dy > dx && dy > mTouchSlop) { - cancelGesture(ev); + if (mAllowGesture) { + logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_VERTICAL_MOVE); + cancelGesture(ev); + } + mLogGesture = false; return; - } else if (dx > dy && dx > mTouchSlop) { - mThresholdCrossed = true; - // Capture inputs - mInputMonitor.pilferPointers(); + if (mAllowGesture) { + mThresholdCrossed = true; + // Capture inputs + mInputMonitor.pilferPointers(); + } else { + logGesture(SysUiStatsLog.BACK_GESTURE__TYPE__INCOMPLETE_FAR_FROM_EDGE); + } } } - } - // forward touch - mEdgeBackPlugin.onMotionEvent(ev); + if (mAllowGesture) { + // forward touch + mEdgeBackPlugin.onMotionEvent(ev); + } } Dependency.get(ProtoTracer.class).update(); 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 496bf68e67a5..bf5900ff24bb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -67,9 +67,9 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC private final Handler mBgHandler; protected final Context mContext; - private int mLevel; - private boolean mPluggedIn; - private boolean mCharging; + protected int mLevel; + protected boolean mPluggedIn; + protected boolean mCharging; private boolean mCharged; private boolean mPowerSave; private boolean mAodPowerSave; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java index 7c963869ed47..c2fc18fe21a1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java @@ -37,10 +37,10 @@ import java.util.Objects; public class WifiSignalController extends SignalController<WifiSignalController.WifiState, SignalController.IconGroup> { - private final boolean mHasMobileData; + private final boolean mHasMobileDataFeature; private final WifiStatusTracker mWifiTracker; - public WifiSignalController(Context context, boolean hasMobileData, + public WifiSignalController(Context context, boolean hasMobileDataFeature, CallbackHandler callbackHandler, NetworkControllerImpl networkController, WifiManager wifiManager) { super("WifiSignalController", context, NetworkCapabilities.TRANSPORT_WIFI, @@ -52,7 +52,7 @@ public class WifiSignalController extends mWifiTracker = new WifiStatusTracker(mContext, wifiManager, networkScoreManager, connectivityManager, this::handleStatusUpdated); mWifiTracker.setListening(true); - mHasMobileData = hasMobileData; + mHasMobileDataFeature = hasMobileDataFeature; if (wifiManager != null) { wifiManager.registerTrafficStateCallback(context.getMainExecutor(), new WifiTrafficStateCallback()); @@ -85,9 +85,10 @@ public class WifiSignalController extends // only show wifi in the cluster if connected or if wifi-only boolean visibleWhenEnabled = mContext.getResources().getBoolean( R.bool.config_showWifiIndicatorWhenEnabled); - boolean wifiVisible = mCurrentState.enabled - && ((mCurrentState.connected && mCurrentState.inetCondition == 1) - || !mHasMobileData || visibleWhenEnabled); + boolean wifiVisible = mCurrentState.enabled && ( + (mCurrentState.connected && mCurrentState.inetCondition == 1) + || !mHasMobileDataFeature || mWifiTracker.isDefaultNetwork + || visibleWhenEnabled); String wifiDesc = mCurrentState.connected ? mCurrentState.ssid : null; boolean ssidPresent = wifiVisible && mCurrentState.ssid != null; String contentDescription = getTextIfExists(getContentDescription()).toString(); diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 9d9ba1bc91b9..eecde7218d28 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -52,6 +52,7 @@ import android.hardware.face.FaceManager; import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; import android.os.Handler; +import android.os.IRemoteCallback; import android.os.UserHandle; import android.os.UserManager; import android.telephony.ServiceState; @@ -63,6 +64,7 @@ import android.testing.TestableContext; import android.testing.TestableLooper; import com.android.internal.telephony.TelephonyIntents; +import com.android.keyguard.KeyguardUpdateMonitor.BiometricAuthenticated; import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dump.DumpManager; @@ -506,6 +508,24 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { } @Test + public void testBiometricsCleared_whenUserSwitches() throws Exception { + final IRemoteCallback reply = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) {} // do nothing + }; + final BiometricAuthenticated dummyAuthentication = + new BiometricAuthenticated(true /* authenticated */, true /* strong */); + mKeyguardUpdateMonitor.mUserFaceAuthenticated.put(0 /* user */, dummyAuthentication); + mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.put(0 /* user */, dummyAuthentication); + assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(1); + assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(1); + + mKeyguardUpdateMonitor.handleUserSwitching(10 /* user */, reply); + assertThat(mKeyguardUpdateMonitor.mUserFingerprintAuthenticated.size()).isEqualTo(0); + assertThat(mKeyguardUpdateMonitor.mUserFaceAuthenticated.size()).isEqualTo(0); + } + + @Test public void testGetUserCanSkipBouncer_whenTrust() { int user = KeyguardUpdateMonitor.getCurrentUser(); mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */, user, 0 /* flags */); diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt index d5a654dc2b6f..eb4d438600d8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt @@ -307,6 +307,7 @@ class ControlsControllerImplTest : SysuiTestCase() { assertEquals(1, controls.size) val controlStatus = controls[0] assertEquals(TEST_CONTROL_ID, controlStatus.control.controlId) + assertEquals(TEST_STRUCTURE_INFO.structure, controlStatus.control.structure) assertTrue(controlStatus.favorite) assertTrue(controlStatus.removed) @@ -337,6 +338,7 @@ class ControlsControllerImplTest : SysuiTestCase() { assertEquals(1, controls.size) val controlStatus = controls[0] assertEquals(TEST_CONTROL_ID, controlStatus.control.controlId) + assertEquals(TEST_STRUCTURE_INFO.structure, controlStatus.control.structure) assertTrue(controlStatus.favorite) assertFalse(controlStatus.removed) diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java index 6112da5cd13b..fe9f60fe2859 100644 --- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java +++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java @@ -37,7 +37,6 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; -import android.util.Size; import android.view.Display; import android.view.View; import android.widget.Toast; @@ -358,8 +357,8 @@ public class WallpaperCropActivity extends Activity { // Get the crop boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR; - Size windowSize = getWindowManager().getCurrentWindowMetrics().getSize(); - boolean isPortrait = windowSize.getWidth() < windowSize.getHeight(); + Rect windowBounds = getWindowManager().getCurrentWindowMetrics().getBounds(); + boolean isPortrait = windowBounds.width() < windowBounds.height(); Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(), getDisplay()); diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 1bb3c3ac0cda..0ddfa1c16a0a 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -886,6 +886,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub { @Override public void setIPv6AddrGenMode(String iface, int mode) throws ServiceSpecificException { + NetworkStack.checkNetworkStackPermission(mContext); try { mNetdService.setIPv6AddrGenMode(iface, mode); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8b2976d0e878..38405e1ccc03 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -185,8 +185,6 @@ import android.app.PendingIntent; import android.app.ProcessMemoryState; import android.app.ProfilerInfo; import android.app.WaitResult; -import android.app.WindowConfiguration.ActivityType; -import android.app.WindowConfiguration.WindowingMode; import android.app.backup.IBackupManager; import android.app.usage.UsageEvents; import android.app.usage.UsageEvents.Event; @@ -6513,13 +6511,6 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public List<RunningTaskInfo> getFilteredTasks(int maxNum, @ActivityType int ignoreActivityType, - @WindowingMode int ignoreWindowingMode) { - return mActivityTaskManager.getFilteredTasks( - maxNum, ignoreActivityType, ignoreWindowingMode); - } - - @Override public void cancelTaskWindowTransition(int taskId) { mActivityTaskManager.cancelTaskWindowTransition(taskId); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 071058c113b2..94675ab7d795 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2324,6 +2324,13 @@ public class AudioService extends IAudioService.Stub // For legacy reason, propagate to all streams associated to this volume group for (final int groupedStream : vgs.getLegacyStreamTypes()) { + try { + ensureValidStreamType(groupedStream); + } catch (IllegalArgumentException e) { + Log.d(TAG, "volume group " + volumeGroup + " has internal streams (" + groupedStream + + "), do not change associated stream volume"); + continue; + } setStreamVolume(groupedStream, index, flags, callingPackage, callingPackage, Binder.getCallingUid()); } @@ -4881,10 +4888,6 @@ public class AudioService extends IAudioService.Stub public void applyAllVolumes() { synchronized (VolumeGroupState.class) { - if (mLegacyStreamType != AudioSystem.STREAM_DEFAULT) { - // No-op to avoid regression with stream based volume management - return; - } // apply device specific volumes first int index; for (int i = 0; i < mIndexMap.size(); i++) { diff --git a/services/core/java/com/android/server/location/RemoteListenerHelper.java b/services/core/java/com/android/server/location/RemoteListenerHelper.java index 11f068533a6d..f6652892c3de 100644 --- a/services/core/java/com/android/server/location/RemoteListenerHelper.java +++ b/services/core/java/com/android/server/location/RemoteListenerHelper.java @@ -273,7 +273,7 @@ public abstract class RemoteListenerHelper<TRequest, TListener extends IInterfac } @Nullable - protected TRequest getRequest() { + public TRequest getRequest() { return mRequest; } } diff --git a/services/core/java/com/android/server/location/ExponentialBackOff.java b/services/core/java/com/android/server/location/gnss/ExponentialBackOff.java index 8c77b2176b74..05a534fa36e9 100644 --- a/services/core/java/com/android/server/location/ExponentialBackOff.java +++ b/services/core/java/com/android/server/location/gnss/ExponentialBackOff.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; /** * A simple implementation of exponential backoff. diff --git a/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java index bc50ebc2c5c3..d839095542c7 100644 --- a/services/core/java/com/android/server/location/GnssAntennaInfoProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssAntennaInfoProvider.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.location; +package com.android.server.location.gnss; import android.content.Context; import android.location.GnssAntennaInfo; @@ -23,6 +23,8 @@ import android.os.Handler; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.location.CallerIdentity; +import com.android.server.location.RemoteListenerHelper; import java.util.List; diff --git a/services/core/java/com/android/server/location/GnssBatchingProvider.java b/services/core/java/com/android/server/location/gnss/GnssBatchingProvider.java index f3918ee9e8ff..f583a3ed3136 100644 --- a/services/core/java/com/android/server/location/GnssBatchingProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssBatchingProvider.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import android.util.Log; diff --git a/services/core/java/com/android/server/location/GnssCapabilitiesProvider.java b/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java index 5c8507f7fde0..71b5b33c242b 100644 --- a/services/core/java/com/android/server/location/GnssCapabilitiesProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssCapabilitiesProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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.server.location; +package com.android.server.location.gnss; import android.location.GnssCapabilities; import android.util.Log; diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java index a3523f23ddcf..14ab79e7ecde 100644 --- a/services/core/java/com/android/server/location/GnssConfiguration.java +++ b/services/core/java/com/android/server/location/gnss/GnssConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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.server.location; +package com.android.server.location.gnss; import android.content.Context; import android.os.PersistableBundle; diff --git a/services/core/java/com/android/server/location/GnssGeofenceProvider.java b/services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java index a84b0b1c4335..53883b91c36d 100644 --- a/services/core/java/com/android/server/location/GnssGeofenceProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssGeofenceProvider.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import android.location.IGpsGeofenceHardware; import android.util.Log; diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java index c1fbcfba864a..ad3c8a61182f 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2020 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.server.location; +package com.android.server.location.gnss; import android.app.AlarmManager; import android.app.AppOpsManager; @@ -78,8 +78,9 @@ import com.android.internal.util.FrameworkStatsLog; import com.android.server.DeviceIdleInternal; import com.android.server.FgThread; import com.android.server.LocalServices; -import com.android.server.location.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback; -import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback; +import com.android.server.location.AbstractLocationProvider; +import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback; +import com.android.server.location.gnss.GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback; import java.io.FileDescriptor; import java.io.PrintWriter; diff --git a/services/core/java/com/android/server/location/gnss/GnssManagerService.java b/services/core/java/com/android/server/location/gnss/GnssManagerService.java index b57c261931f8..9e64e3aeae59 100644 --- a/services/core/java/com/android/server/location/gnss/GnssManagerService.java +++ b/services/core/java/com/android/server/location/gnss/GnssManagerService.java @@ -55,14 +55,6 @@ import com.android.server.LocationManagerServiceUtils.LinkedListener; import com.android.server.LocationManagerServiceUtils.LinkedListenerBase; import com.android.server.location.AppForegroundHelper; import com.android.server.location.CallerIdentity; -import com.android.server.location.GnssAntennaInfoProvider; -import com.android.server.location.GnssBatchingProvider; -import com.android.server.location.GnssCapabilitiesProvider; -import com.android.server.location.GnssLocationProvider; -import com.android.server.location.GnssMeasurementCorrectionsProvider; -import com.android.server.location.GnssMeasurementsProvider; -import com.android.server.location.GnssNavigationMessageProvider; -import com.android.server.location.GnssStatusListenerHelper; import com.android.server.location.LocationUsageLogger; import com.android.server.location.RemoteListenerHelper; import com.android.server.location.SettingsHelper; diff --git a/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java index 82528caa0b4e..ac165d1a206b 100644 --- a/services/core/java/com/android/server/location/GnssMeasurementCorrectionsProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementCorrectionsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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.server.location; +package com.android.server.location.gnss; import android.location.GnssMeasurementCorrections; import android.os.Handler; diff --git a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java index 6ba5f079264c..76c3ad02e7e9 100644 --- a/services/core/java/com/android/server/location/GnssMeasurementsProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2020 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.server.location; +package com.android.server.location.gnss; import android.content.Context; import android.location.GnssMeasurementsEvent; @@ -26,6 +26,8 @@ import android.provider.Settings; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.location.CallerIdentity; +import com.android.server.location.RemoteListenerHelper; /** * An base implementation for GPS measurements provider. It abstracts out the responsibility of diff --git a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java index fb901e86f494..722be3df2691 100644 --- a/services/core/java/com/android/server/location/GnssNavigationMessageProvider.java +++ b/services/core/java/com/android/server/location/gnss/GnssNavigationMessageProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2020 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.server.location; +package com.android.server.location.gnss; import android.content.Context; import android.location.GnssNavigationMessage; @@ -24,6 +24,8 @@ import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.location.CallerIdentity; +import com.android.server.location.RemoteListenerHelper; /** * An base implementation for GPS navigation messages provider. diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java index 5d6474bdbccc..3fb713bc01a5 100644 --- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java +++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2020 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.server.location; +package com.android.server.location.gnss; import android.content.Context; import android.database.Cursor; diff --git a/services/core/java/com/android/server/location/GnssPositionMode.java b/services/core/java/com/android/server/location/gnss/GnssPositionMode.java index 36838fc3647f..045118afbda0 100644 --- a/services/core/java/com/android/server/location/GnssPositionMode.java +++ b/services/core/java/com/android/server/location/gnss/GnssPositionMode.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import java.util.Arrays; diff --git a/services/core/java/com/android/server/location/GnssSatelliteBlacklistHelper.java b/services/core/java/com/android/server/location/gnss/GnssSatelliteBlacklistHelper.java index eb99a851115f..dccef9b9a9c4 100644 --- a/services/core/java/com/android/server/location/GnssSatelliteBlacklistHelper.java +++ b/services/core/java/com/android/server/location/gnss/GnssSatelliteBlacklistHelper.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import android.content.ContentResolver; import android.content.Context; diff --git a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java b/services/core/java/com/android/server/location/gnss/GnssStatusListenerHelper.java index 1d16c03fd6f7..d2ecdeebd9d0 100644 --- a/services/core/java/com/android/server/location/GnssStatusListenerHelper.java +++ b/services/core/java/com/android/server/location/gnss/GnssStatusListenerHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 The Android Open Source Project + * Copyright (C) 2020 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. @@ -11,16 +11,19 @@ * 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 + * limitations under the License. */ -package com.android.server.location; +package com.android.server.location.gnss; import android.content.Context; import android.location.IGnssStatusListener; import android.os.Handler; import android.util.Log; +import com.android.server.location.CallerIdentity; +import com.android.server.location.RemoteListenerHelper; + /** * Implementation of a handler for {@link IGnssStatusListener}. */ diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java index 2b5fc7989d8b..06fa0ea7791d 100644 --- a/services/core/java/com/android/server/location/GnssVisibilityControl.java +++ b/services/core/java/com/android/server/location/gnss/GnssVisibilityControl.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2020 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.server.location; +package com.android.server.location.gnss; import android.annotation.Nullable; import android.annotation.SuppressLint; diff --git a/services/core/java/com/android/server/location/GpsPsdsDownloader.java b/services/core/java/com/android/server/location/gnss/GpsPsdsDownloader.java index 6fcb7d1af2ce..273f9cb13a1b 100644 --- a/services/core/java/com/android/server/location/GpsPsdsDownloader.java +++ b/services/core/java/com/android/server/location/gnss/GpsPsdsDownloader.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2020 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.server.location; +package com.android.server.location.gnss; import android.net.TrafficStats; import android.text.TextUtils; diff --git a/services/core/java/com/android/server/location/NtpTimeHelper.java b/services/core/java/com/android/server/location/gnss/NtpTimeHelper.java index d2296ea27913..2bbb61fbe018 100644 --- a/services/core/java/com/android/server/location/NtpTimeHelper.java +++ b/services/core/java/com/android/server/location/gnss/NtpTimeHelper.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import android.content.Context; import android.net.ConnectivityManager; @@ -12,6 +28,7 @@ import android.util.NtpTrustedTime; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.location.gnss.ExponentialBackOff; import java.util.Date; diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index c37ea8ba68bd..c97f33b5103f 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -16,22 +16,22 @@ package com.android.server.pm; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; + import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.ApexInfo; import android.apex.ApexInfoList; import android.apex.ApexSessionInfo; import android.apex.ApexSessionParams; import android.apex.IApexService; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageParser; +import android.content.pm.parsing.PackageInfoWithoutStateUtils; import android.os.Environment; import android.os.RemoteException; import android.os.ServiceManager; @@ -44,8 +44,9 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.os.BackgroundThread; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; +import com.android.server.pm.parsing.PackageParser2; import com.android.server.pm.parsing.pkg.AndroidPackage; import com.android.server.utils.TimingsTraceAndSlog; @@ -61,7 +62,9 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; +import java.util.concurrent.ExecutorService; import java.util.stream.Collectors; /** @@ -72,7 +75,7 @@ public abstract class ApexManager { private static final String TAG = "ApexManager"; - static final int MATCH_ACTIVE_PACKAGE = 1 << 0; + public static final int MATCH_ACTIVE_PACKAGE = 1 << 0; static final int MATCH_FACTORY_PACKAGE = 1 << 1; private static final Singleton<ApexManager> sApexManagerSingleton = @@ -139,7 +142,14 @@ public abstract class ApexManager { */ public abstract List<ActiveApexInfo> getActiveApexInfos(); - abstract void systemReady(Context context); + /** + * Called by package manager service to scan apex package files when device boots up. + * + * @param packageParser The package parser which supports caches. + * @param executorService An executor to support parallel package parsing. + */ + abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser, + @NonNull ExecutorService executorService); /** * Retrieves information about an APEX package. @@ -154,7 +164,7 @@ public abstract class ApexManager { * is not found. */ @Nullable - abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags); + public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags); /** * Retrieves information about all active APEX packages. @@ -189,6 +199,27 @@ public abstract class ApexManager { abstract boolean isApexPackage(String packageName); /** + * Whether the APEX package is pre-installed or not. + * + * @param packageInfo the package to check + * @return {@code true} if this package is pre-installed, {@code false} otherwise. + */ + public static boolean isFactory(@NonNull PackageInfo packageInfo) { + return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + /** + * Returns the active apex package's name that contains the (apk) package. + * + * @param containedPackage The (apk) package that might be in a apex + * @return the apex package's name of {@code null} if the {@code containedPackage} is not inside + * any apex. + */ + @Nullable + public abstract String getActiveApexPackageNameContainingPackage( + @NonNull AndroidPackage containedPackage); + + /** * Retrieves information about an apexd staged session i.e. the internal state used by apexd to * track the different states of a session. * @@ -342,7 +373,7 @@ public abstract class ApexManager { * difference between {@code packageName} and {@code apexModuleName}. */ @GuardedBy("mLock") - private Map<String, List<String>> mApksInApex = new ArrayMap<>(); + private ArrayMap<String, List<String>> mApksInApex = new ArrayMap<>(); @GuardedBy("mLock") private List<PackageInfo> mAllPackagesCache; @@ -357,7 +388,7 @@ public abstract class ApexManager { * the apk container to {@code apexModuleName} of the apex-payload inside. */ @GuardedBy("mLock") - private Map<String, String> mPackageNameToApexModuleName; + private ArrayMap<String, String> mPackageNameToApexModuleName; ApexManagerImpl(IApexService apexService) { mApexService = apexService; @@ -373,16 +404,6 @@ public abstract class ApexManager { return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0; } - /** - * Whether the APEX package is pre-installed or not. - * - * @param packageInfo the package to check - * @return {@code true} if this package is pre-installed, {@code false} otherwise. - */ - private static boolean isFactory(PackageInfo packageInfo) { - return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; - } - @Override public List<ActiveApexInfo> getActiveApexInfos() { final TimingsTraceAndSlog t = new TimingsTraceAndSlog(TAG + "Timing", @@ -411,104 +432,94 @@ public abstract class ApexManager { } @Override - void systemReady(Context context) { - context.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // Post populateAllPackagesCacheIfNeeded to a background thread, since it's - // expensive to run it in broadcast handler thread. - BackgroundThread.getHandler().post(() -> populateAllPackagesCacheIfNeeded()); - context.unregisterReceiver(this); - } - }, new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); - } - - private void populatePackageNameToApexModuleNameIfNeeded() { - synchronized (mLock) { - if (mPackageNameToApexModuleName != null) { - return; - } - try { - mPackageNameToApexModuleName = new ArrayMap<>(); - final ApexInfo[] allPkgs = mApexService.getAllPackages(); - for (int i = 0; i < allPkgs.length; i++) { - ApexInfo ai = allPkgs[i]; - PackageParser.PackageLite pkgLite; - try { - File apexFile = new File(ai.modulePath); - pkgLite = PackageParser.parsePackageLite(apexFile, 0); - } catch (PackageParser.PackageParserException pe) { - throw new IllegalStateException("Unable to parse: " - + ai.modulePath, pe); - } - mPackageNameToApexModuleName.put(pkgLite.packageName, ai.moduleName); - } - } catch (RemoteException re) { - Slog.e(TAG, "Unable to retrieve packages from apexservice: ", re); - throw new RuntimeException(re); + void scanApexPackagesTraced(@NonNull PackageParser2 packageParser, + @NonNull ExecutorService executorService) { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanApexPackagesTraced"); + try { + synchronized (mLock) { + scanApexPackagesInternalLocked(packageParser, executorService); } + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } - private void populateAllPackagesCacheIfNeeded() { - synchronized (mLock) { - if (mAllPackagesCache != null) { - return; - } - try { - mAllPackagesCache = new ArrayList<>(); - HashSet<String> activePackagesSet = new HashSet<>(); - HashSet<String> factoryPackagesSet = new HashSet<>(); - final ApexInfo[] allPkgs = mApexService.getAllPackages(); - for (ApexInfo ai : allPkgs) { - // If the device is using flattened APEX, don't report any APEX - // packages since they won't be managed or updated by PackageManager. - if ((new File(ai.modulePath)).isDirectory()) { - break; - } - int flags = PackageManager.GET_META_DATA - | PackageManager.GET_SIGNING_CERTIFICATES - | PackageManager.GET_SIGNATURES; - PackageParser.Package pkg; - try { - File apexFile = new File(ai.modulePath); - PackageParser pp = new PackageParser(); - pkg = pp.parsePackage(apexFile, flags, false); - PackageParser.collectCertificates(pkg, false); - } catch (PackageParser.PackageParserException pe) { - throw new IllegalStateException("Unable to parse: " + ai, pe); - } + @GuardedBy("mLock") + private void scanApexPackagesInternalLocked(PackageParser2 packageParser, + ExecutorService executorService) { + final ApexInfo[] allPkgs; + try { + mAllPackagesCache = new ArrayList<>(); + mPackageNameToApexModuleName = new ArrayMap<>(); + allPkgs = mApexService.getAllPackages(); + } catch (RemoteException re) { + Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); + throw new RuntimeException(re); + } + if (allPkgs.length == 0) { + return; + } + int flags = PackageManager.GET_META_DATA + | PackageManager.GET_SIGNING_CERTIFICATES + | PackageManager.GET_SIGNATURES; + ArrayMap<File, ApexInfo> parsingApexInfo = new ArrayMap<>(); + ParallelPackageParser parallelPackageParser = + new ParallelPackageParser(packageParser, executorService); + + for (ApexInfo ai : allPkgs) { + File apexFile = new File(ai.modulePath); + parallelPackageParser.submit(apexFile, flags); + parsingApexInfo.put(apexFile, ai); + } - final PackageInfo packageInfo = - PackageParser.generatePackageInfo(pkg, ai, flags); - mAllPackagesCache.add(packageInfo); - if (ai.isActive) { - if (activePackagesSet.contains(packageInfo.packageName)) { - throw new IllegalStateException( - "Two active packages have the same name: " - + packageInfo.packageName); - } - activePackagesSet.add(packageInfo.packageName); + HashSet<String> activePackagesSet = new HashSet<>(); + HashSet<String> factoryPackagesSet = new HashSet<>(); + // Process results one by one + for (int i = 0; i < parsingApexInfo.size(); i++) { + ParallelPackageParser.ParseResult parseResult = parallelPackageParser.take(); + Throwable throwable = parseResult.throwable; + ApexInfo ai = parsingApexInfo.get(parseResult.scanFile); + + if (throwable == null) { + final PackageInfo packageInfo = PackageInfoWithoutStateUtils.generate( + parseResult.parsedPackage, ai, flags); + if (packageInfo == null) { + throw new IllegalStateException("Unable to generate package info: " + + ai.modulePath); + } + mAllPackagesCache.add(packageInfo); + mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName); + if (ai.isActive) { + if (activePackagesSet.contains(packageInfo.packageName)) { + throw new IllegalStateException( + "Two active packages have the same name: " + + packageInfo.packageName); } - if (ai.isFactory) { - if (factoryPackagesSet.contains(packageInfo.packageName)) { - throw new IllegalStateException( - "Two factory packages have the same name: " - + packageInfo.packageName); - } - factoryPackagesSet.add(packageInfo.packageName); + activePackagesSet.add(packageInfo.packageName); + } + if (ai.isFactory) { + if (factoryPackagesSet.contains(packageInfo.packageName)) { + throw new IllegalStateException( + "Two factory packages have the same name: " + + packageInfo.packageName); } + factoryPackagesSet.add(packageInfo.packageName); } - } catch (RemoteException re) { - Slog.e(TAG, "Unable to retrieve packages from apexservice: " + re.toString()); - throw new RuntimeException(re); + } else if (throwable instanceof PackageParser.PackageParserException) { + throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable); + } else { + throw new IllegalStateException("Unexpected exception occurred while parsing " + + ai.modulePath, throwable); } } } @Override - @Nullable PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) { - populateAllPackagesCacheIfNeeded(); + @Nullable + public PackageInfo getPackageInfo(String packageName, + @PackageInfoFlags int flags) { + Preconditions.checkState(mAllPackagesCache != null, + "APEX packages have not been scanned"); boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0; boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0; for (PackageInfo packageInfo: mAllPackagesCache) { @@ -525,7 +536,8 @@ public abstract class ApexManager { @Override List<PackageInfo> getActivePackages() { - populateAllPackagesCacheIfNeeded(); + Preconditions.checkState(mAllPackagesCache != null, + "APEX packages have not been scanned"); return mAllPackagesCache .stream() .filter(item -> isActive(item)) @@ -534,7 +546,8 @@ public abstract class ApexManager { @Override List<PackageInfo> getFactoryPackages() { - populateAllPackagesCacheIfNeeded(); + Preconditions.checkState(mAllPackagesCache != null, + "APEX packages have not been scanned"); return mAllPackagesCache .stream() .filter(item -> isFactory(item)) @@ -543,7 +556,8 @@ public abstract class ApexManager { @Override List<PackageInfo> getInactivePackages() { - populateAllPackagesCacheIfNeeded(); + Preconditions.checkState(mAllPackagesCache != null, + "APEX packages have not been scanned"); return mAllPackagesCache .stream() .filter(item -> !isActive(item)) @@ -553,7 +567,8 @@ public abstract class ApexManager { @Override boolean isApexPackage(String packageName) { if (!isApexSupported()) return false; - populateAllPackagesCacheIfNeeded(); + Preconditions.checkState(mAllPackagesCache != null, + "APEX packages have not been scanned"); for (PackageInfo packageInfo : mAllPackagesCache) { if (packageInfo.packageName.equals(packageName)) { return true; @@ -563,6 +578,36 @@ public abstract class ApexManager { } @Override + @Nullable + public String getActiveApexPackageNameContainingPackage( + @NonNull AndroidPackage containedPackage) { + Preconditions.checkState(mPackageNameToApexModuleName != null, + "APEX packages have not been scanned"); + + Objects.requireNonNull(containedPackage); + + synchronized (mLock) { + int numApksInApex = mApksInApex.size(); + for (int apkInApexNum = 0; apkInApexNum < numApksInApex; apkInApexNum++) { + if (mApksInApex.valueAt(apkInApexNum).contains( + containedPackage.getPackageName())) { + String apexModuleName = mApksInApex.keyAt(apkInApexNum); + + int numApexPkgs = mPackageNameToApexModuleName.size(); + for (int apexPkgNum = 0; apexPkgNum < numApexPkgs; apexPkgNum++) { + if (mPackageNameToApexModuleName.valueAt(apexPkgNum).equals( + apexModuleName)) { + return mPackageNameToApexModuleName.keyAt(apexPkgNum); + } + } + } + } + } + + return null; + } + + @Override @Nullable ApexSessionInfo getStagedSessionInfo(int sessionId) { try { ApexSessionInfo apexSessionInfo = mApexService.getStagedSessionInfo(sessionId); @@ -684,8 +729,9 @@ public abstract class ApexManager { @Override List<String> getApksInApex(String apexPackageName) { - populatePackageNameToApexModuleNameIfNeeded(); synchronized (mLock) { + Preconditions.checkState(mPackageNameToApexModuleName != null, + "APEX packages have not been scanned"); String moduleName = mPackageNameToApexModuleName.get(apexPackageName); if (moduleName == null) { return Collections.emptyList(); @@ -697,17 +743,19 @@ public abstract class ApexManager { @Override @Nullable public String getApexModuleNameForPackageName(String apexPackageName) { - populatePackageNameToApexModuleNameIfNeeded(); synchronized (mLock) { + Preconditions.checkState(mPackageNameToApexModuleName != null, + "APEX packages have not been scanned"); return mPackageNameToApexModuleName.get(apexPackageName); } } @Override public long snapshotCeData(int userId, int rollbackId, String apexPackageName) { - populatePackageNameToApexModuleNameIfNeeded(); String apexModuleName; synchronized (mLock) { + Preconditions.checkState(mPackageNameToApexModuleName != null, + "APEX packages have not been scanned"); apexModuleName = mPackageNameToApexModuleName.get(apexPackageName); } if (apexModuleName == null) { @@ -724,9 +772,10 @@ public abstract class ApexManager { @Override public boolean restoreCeData(int userId, int rollbackId, String apexPackageName) { - populatePackageNameToApexModuleNameIfNeeded(); String apexModuleName; synchronized (mLock) { + Preconditions.checkState(mPackageNameToApexModuleName != null, + "APEX packages have not been scanned"); apexModuleName = mPackageNameToApexModuleName.get(apexPackageName); } if (apexModuleName == null) { @@ -797,15 +846,7 @@ public abstract class ApexManager { void dump(PrintWriter pw, @Nullable String packageName) { final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120); try { - populateAllPackagesCacheIfNeeded(); ipw.println(); - ipw.println("Active APEX packages:"); - dumpFromPackagesCache(getActivePackages(), packageName, ipw); - ipw.println("Inactive APEX packages:"); - dumpFromPackagesCache(getInactivePackages(), packageName, ipw); - ipw.println("Factory APEX packages:"); - dumpFromPackagesCache(getFactoryPackages(), packageName, ipw); - ipw.increaseIndent(); ipw.println("APEX session state:"); ipw.increaseIndent(); final ApexSessionInfo[] sessions = mApexService.getSessions(); @@ -834,6 +875,17 @@ public abstract class ApexManager { ipw.decreaseIndent(); } ipw.decreaseIndent(); + ipw.println(); + if (mAllPackagesCache == null) { + ipw.println("APEX packages have not been scanned"); + return; + } + ipw.println("Active APEX packages:"); + dumpFromPackagesCache(getActivePackages(), packageName, ipw); + ipw.println("Inactive APEX packages:"); + dumpFromPackagesCache(getInactivePackages(), packageName, ipw); + ipw.println("Factory APEX packages:"); + dumpFromPackagesCache(getFactoryPackages(), packageName, ipw); } catch (RemoteException e) { ipw.println("Couldn't communicate with apexd."); } @@ -879,12 +931,13 @@ public abstract class ApexManager { } @Override - void systemReady(Context context) { + void scanApexPackagesTraced(@NonNull PackageParser2 packageParser, + @NonNull ExecutorService executorService) { // No-op } @Override - PackageInfo getPackageInfo(String packageName, int flags) { + public PackageInfo getPackageInfo(String packageName, int flags) { return null; } @@ -909,6 +962,15 @@ public abstract class ApexManager { } @Override + @Nullable + public String getActiveApexPackageNameContainingPackage( + @NonNull AndroidPackage containedPackage) { + Objects.requireNonNull(containedPackage); + + return null; + } + + @Override ApexSessionInfo getStagedSessionInfo(int sessionId) { throw new UnsupportedOperationException(); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 2ff3d2a3a938..8ff7ea9d61dd 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -490,6 +490,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements throw new SecurityException("User restriction prevents installing"); } + if (params.dataLoaderParams != null + && mContext.checkCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need the " + + "com.android.permission.USE_INSTALLER_V2 permission " + + "to use a data loader"); + } + String requestedInstallerPackageName = params.installerPackageName != null ? params.installerPackageName : installerPackageName; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 348a4cb77163..1248ec01e020 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -2479,12 +2479,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public DataLoaderParamsParcel getDataLoaderParams() { + mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null); return params.dataLoaderParams != null ? params.dataLoaderParams.getData() : null; } @Override public void addFile(int location, String name, long lengthBytes, byte[] metadata, byte[] signature) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null); if (!isDataLoaderInstallation()) { throw new IllegalStateException( "Cannot add files to non-data loader installation session."); @@ -2517,6 +2519,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void removeFile(int location, String name) { + mContext.enforceCallingOrSelfPermission(Manifest.permission.USE_INSTALLER_V2, null); if (!isDataLoaderInstallation()) { throw new IllegalStateException( "Cannot add files to non-data loader installation session."); @@ -3242,8 +3245,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { new ComponentName( readStringAttribute(in, ATTR_DATALOADER_PACKAGE_NAME), readStringAttribute(in, ATTR_DATALOADER_CLASS_NAME)), - readStringAttribute(in, ATTR_DATALOADER_ARGUMENTS), - null); + readStringAttribute(in, ATTR_DATALOADER_ARGUMENTS)); } final File appIconFile = buildAppIconFile(sessionId, sessionsDir); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 58a9d9c5f6bf..34363c8df8f6 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2900,6 +2900,9 @@ public class PackageManagerService extends IPackageManager.Stub mMetrics, mCacheDir, mPackageParserCallback); ExecutorService executorService = ParallelPackageParser.makeExecutorService(); + // Prepare apex package info before scanning APKs, these information are needed when + // scanning apk in apex. + mApexManager.scanApexPackagesTraced(packageParser, executorService); // Collect vendor/product/system_ext overlay packages. (Do this before scanning // any apps.) // For security and version matching reason, only consider overlay packages if they @@ -20696,7 +20699,6 @@ public class PackageManagerService extends IPackageManager.Stub storage.registerListener(mStorageListener); mInstallerService.systemReady(); - mApexManager.systemReady(mContext); mPackageDexOptimizer.systemReady(); mInjector.getStorageManagerInternal().addExternalStoragePolicy( diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 04c965e69588..765ecb9710cb 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -42,6 +42,7 @@ import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.permission.PermissionManager.KILL_APP_REASON_GIDS_CHANGED; import static android.permission.PermissionManager.KILL_APP_REASON_PERMISSIONS_REVOKED; +import static com.android.server.pm.ApexManager.MATCH_ACTIVE_PACKAGE; import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS; @@ -130,6 +131,7 @@ import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemConfig; import com.android.server.Watchdog; +import com.android.server.pm.ApexManager; import com.android.server.pm.PackageManagerServiceUtils; import com.android.server.pm.PackageSetting; import com.android.server.pm.SharedUserSetting; @@ -3317,8 +3319,16 @@ public class PermissionManagerService extends IPermissionManager.Stub { if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged() && !platformPackage && platformPermission) { if (!hasPrivappWhitelistEntry(perm, pkg)) { - // Only report violations for apps on system image - if (!mSystemReady && !pkgSetting.getPkgState().isUpdatedSystemApp()) { + ApexManager apexMgr = ApexManager.getInstance(); + String apexContainingPkg = apexMgr.getActiveApexPackageNameContainingPackage(pkg); + + // Only enforce whitelist this on boot + if (!mSystemReady + // Updated system apps do not need to be whitelisted + && !pkgSetting.getPkgState().isUpdatedSystemApp() + // Apps that are in updated apexs' do not need to be whitelisted + && (apexContainingPkg == null || apexMgr.isFactory( + apexMgr.getPackageInfo(apexContainingPkg, MATCH_ACTIVE_PACKAGE)))) { // it's only a reportable violation if the permission isn't explicitly denied ArraySet<String> deniedPermissions = null; if (pkg.isVendor()) { diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java index b051bab71f12..8ff2a1b6364b 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java @@ -37,9 +37,9 @@ class TimeZoneDetectorShellCommand extends ShellCommand { } switch (cmd) { - case "suggestTelephonyTimeZone": + case "suggest_telephony_time_zone": return runSuggestTelephonyTimeZone(); - case "suggestManualTimeZone": + case "suggest_manual_time_zone": return runSuggestManualTimeZone(); default: { return handleDefaultCommands(cmd); @@ -105,9 +105,9 @@ class TimeZoneDetectorShellCommand extends ShellCommand { pw.println("Time Zone Detector (time_zone_detector) commands:"); pw.println(" help"); pw.println(" Print this help text."); - pw.println(" suggestTelephonyTimeZone"); + pw.println(" suggest_telephony_time_zone"); pw.println(" --suggestion <telephony suggestion opts>"); - pw.println(" suggestManualTimeZone"); + pw.println(" suggest_manual_time_zone"); pw.println(" --suggestion <manual suggestion opts>"); pw.println(); ManualTimeZoneSuggestion.printCommandLineOpts(pw); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 2378813e78b3..90898597c265 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -2342,8 +2342,7 @@ class ActivityStack extends Task { if (!newTask && isOrhasTask) { // Starting activity cannot be occluding activity, otherwise starting window could be // remove immediately without transferring to starting activity. - final ActivityRecord occludingActivity = getActivity( - (ar) -> ar.occludesParent(), true, r); + final ActivityRecord occludingActivity = getOccludingActivityAbove(r); if (occludingActivity != null) { // Here it is! Now, if this is not yet visible (occluded by another task) to the // user, then just add it without starting; it will get started when the user @@ -3069,6 +3068,14 @@ class ActivityStack extends Task { task.setOverrideDisplayedBounds(bounds == null || bounds.isEmpty() ? null : bounds); } + /** + * Returns the top-most activity that occludes the given one, or @{code null} if none. + */ + @Nullable + private ActivityRecord getOccludingActivityAbove(ActivityRecord activity) { + return getActivity((ar) -> ar.occludesParent(), true /* traverseTopToBottom */, activity); + } + boolean willActivityBeVisible(IBinder token) { final ActivityRecord r = ActivityRecord.forTokenLocked(token); if (r == null) { @@ -3076,8 +3083,7 @@ class ActivityStack extends Task { } // See if there is an occluding activity on-top of this one. - final ActivityRecord occludingActivity = getActivity((ar) -> ar.occludesParent(), r, - false /*includeBoundary*/, true /*traverseTopToBottom*/); + final ActivityRecord occludingActivity = getOccludingActivityAbove(r); if (occludingActivity != null) return false; if (r.finishing) Slog.e(TAG, "willActivityBeVisible: Returning false," diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index a5b0026398b6..bf92542cdd63 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -32,7 +32,6 @@ import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_PRESERVE_WINDOW; import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; @@ -2615,13 +2614,16 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { @Override public List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) { - return getFilteredTasks(maxNum, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED); + return getFilteredTasks(maxNum, false /* filterForVisibleRecents */); } + /** + * @param filterOnlyVisibleRecents whether to filter the tasks based on whether they would ever + * be visible in the recent task list in systemui + */ @Override public List<ActivityManager.RunningTaskInfo> getFilteredTasks(int maxNum, - @WindowConfiguration.ActivityType int ignoreActivityType, - @WindowConfiguration.WindowingMode int ignoreWindowingMode) { + boolean filterOnlyVisibleRecents) { final int callingUid = Binder.getCallingUid(); final int callingPid = Binder.getCallingPid(); final boolean crossUser = isCrossUserAllowed(callingPid, callingUid); @@ -2637,8 +2639,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { if (DEBUG_ALL) Slog.v(TAG, "getTasks: max=" + maxNum); final boolean allowed = isGetTasksAllowed("getTasks", callingPid, callingUid); - mRootWindowContainer.getRunningTasks(maxNum, list, ignoreActivityType, - ignoreWindowingMode, callingUid, allowed, crossUser, callingProfileIds); + mRootWindowContainer.getRunningTasks(maxNum, list, filterOnlyVisibleRecents, callingUid, + allowed, crossUser, callingProfileIds); } return list; diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 6a47c9e217f8..654ccc80f8a8 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -618,6 +618,7 @@ public class AppTransitionController { Animation anim = mService.mPolicy.createKeyguardWallpaperExit( (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0); if (anim != null) { + anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked()); mDisplayContent.mWallpaperController.startWallpaperAnimation(anim); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index a90016afcc49..88c9b2cc0cb9 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3209,7 +3209,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (mode == UPDATE_FOCUS_PLACING_SURFACES) { performLayout(true /*initial*/, updateInputWindows); } else if (mode == UPDATE_FOCUS_REMOVING_FOCUS) { - mWmService.mRoot.performSurfacePlacement(false); + mWmService.mRoot.performSurfacePlacement(); } } @@ -3846,7 +3846,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } // TODO: Super crazy long method that should be broken down... - void applySurfaceChangesTransaction(boolean recoveringMemory) { + void applySurfaceChangesTransaction() { final WindowSurfacePlacer surfacePlacer = mWmService.mWindowPlacerLocked; mTmpUpdateAllDrawn.clear(); diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java index 244ba82ce32c..12be9df55fad 100644 --- a/services/core/java/com/android/server/wm/RecentTasks.java +++ b/services/core/java/com/android/server/wm/RecentTasks.java @@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; @@ -1309,6 +1310,7 @@ class RecentTasks { == FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) { return false; } + break; } // Ignore certain windowing modes @@ -1316,23 +1318,21 @@ class RecentTasks { case WINDOWING_MODE_PINNED: return false; case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY: - if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "\ttop=" + task.getStack().getTopMostTask()); + if (DEBUG_RECENTS_TRIM_TASKS) { + Slog.d(TAG, "\ttop=" + task.getStack().getTopMostTask()); + } final ActivityStack stack = task.getStack(); if (stack != null && stack.getTopMostTask() == task) { // Only the non-top task of the primary split screen mode is visible return false; } - } - - // Tasks managed by/associated with an ActivityView should be excluded from recents. - // singleTaskInstance is set on the VirtualDisplay managed by ActivityView - // TODO(b/126185105): Find a different signal to use besides isSingleTaskInstance - final ActivityStack stack = task.getStack(); - if (stack != null) { - DisplayContent display = stack.getDisplay(); - if (display != null && display.isSingleTaskInstance()) { - return false; - } + break; + case WINDOWING_MODE_MULTI_WINDOW: + // Ignore tasks that are always on top + if (task.isAlwaysOnTop()) { + return false; + } + break; } // If we're in lock task mode, ignore the root task diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java index 9089240fe9d1..057592c0c2fc 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimation.java +++ b/services/core/java/com/android/server/wm/RecentsAnimation.java @@ -400,6 +400,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks, throw e; } finally { mService.continueWindowLayout(); + // Make sure the surfaces are updated with the latest state. Sometimes the + // surface placement may be skipped if display configuration is changed (i.e. + // {@link DisplayContent#mWaitingForConfig} is true). + if (mWindowManager.mRoot.isLayoutNeeded()) { + mWindowManager.mRoot.performSurfacePlacement(); + } Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } }); diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 6e56bf4dafd7..ff174278878f 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -796,10 +796,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return leakedSurface || killedApps; } - void performSurfacePlacement(boolean recoveringMemory) { + void performSurfacePlacement() { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "performSurfacePlacement"); try { - performSurfacePlacementNoTrace(recoveringMemory); + performSurfacePlacementNoTrace(); } finally { Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); } @@ -807,7 +807,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // "Something has changed! Let's make it correct now." // TODO: Super crazy long method that should be broken down... - void performSurfacePlacementNoTrace(boolean recoveringMemory) { + void performSurfacePlacementNoTrace() { if (DEBUG_WINDOW_TRACE) Slog.v(TAG, "performSurfacePlacementInner: entry. Called by " + Debug.getCallers(3)); @@ -842,7 +842,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "applySurfaceChanges"); mWmService.openSurfaceTransaction(); try { - applySurfaceChangesTransaction(recoveringMemory); + applySurfaceChangesTransaction(); } catch (RuntimeException e) { Slog.wtf(TAG, "Unhandled exception in Window Manager", e); } finally { @@ -1042,7 +1042,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - private void applySurfaceChangesTransaction(boolean recoveringMemory) { + private void applySurfaceChangesTransaction() { mHoldScreenWindow = null; mObscuringWindow = null; @@ -1065,7 +1065,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> final int count = mChildren.size(); for (int j = 0; j < count; ++j) { final DisplayContent dc = mChildren.get(j); - dc.applySurfaceChangesTransaction(recoveringMemory); + dc.applySurfaceChangesTransaction(); } // Give the display manager a chance to adjust properties like display rotation if it needs @@ -3393,11 +3393,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> @VisibleForTesting void getRunningTasks(int maxNum, List<ActivityManager.RunningTaskInfo> list, - @WindowConfiguration.ActivityType int ignoreActivityType, - @WindowConfiguration.WindowingMode int ignoreWindowingMode, int callingUid, - boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) { - mStackSupervisor.getRunningTasks().getTasks(maxNum, list, ignoreActivityType, - ignoreWindowingMode, this, callingUid, allowed, crossUser, profileIds); + boolean filterOnlyVisibleRecents, int callingUid, boolean allowed, boolean crossUser, + ArraySet<Integer> profileIds) { + mStackSupervisor.getRunningTasks().getTasks(maxNum, list, filterOnlyVisibleRecents, this, + callingUid, allowed, crossUser, profileIds); } void sendPowerHintForLaunchStartIfNeeded(boolean forceSend, ActivityRecord targetActivity) { diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java index 02077fbf453e..3509ba72d058 100644 --- a/services/core/java/com/android/server/wm/RunningTasks.java +++ b/services/core/java/com/android/server/wm/RunningTasks.java @@ -16,12 +16,10 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import android.app.ActivityManager.RunningTaskInfo; -import android.app.WindowConfiguration.ActivityType; -import android.app.WindowConfiguration.WindowingMode; import android.os.UserHandle; import android.util.ArraySet; @@ -49,13 +47,13 @@ class RunningTasks { private boolean mCrossUser; private ArraySet<Integer> mProfileIds; private boolean mAllowed; - private int mIgnoreActivityType; - private int mIgnoreWindowingMode; + private boolean mFilterOnlyVisibleRecents; private ActivityStack mTopDisplayFocusStack; + private RecentTasks mRecentTasks; - void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType, - @WindowingMode int ignoreWindowingMode, RootWindowContainer root, - int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) { + void getTasks(int maxNum, List<RunningTaskInfo> list, boolean filterOnlyVisibleRecents, + RootWindowContainer root, int callingUid, boolean allowed, boolean crossUser, + ArraySet<Integer> profileIds) { // Return early if there are no tasks to fetch if (maxNum <= 0) { return; @@ -68,9 +66,9 @@ class RunningTasks { mCrossUser = crossUser; mProfileIds = profileIds; mAllowed = allowed; - mIgnoreActivityType = ignoreActivityType; - mIgnoreWindowingMode = ignoreWindowingMode; + mFilterOnlyVisibleRecents = filterOnlyVisibleRecents; mTopDisplayFocusStack = root.getTopDisplayFocusedStack(); + mRecentTasks = root.mService.getRecentTasks(); final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this, PooledLambda.__(Task.class)); @@ -107,14 +105,12 @@ class RunningTasks { return; } } - if (mIgnoreActivityType != ACTIVITY_TYPE_UNDEFINED - && task.getActivityType() == mIgnoreActivityType) { - // Skip ignored activity type - return; - } - if (mIgnoreWindowingMode != WINDOWING_MODE_UNDEFINED - && task.getWindowingMode() == mIgnoreWindowingMode) { - // Skip ignored windowing mode + if (mFilterOnlyVisibleRecents + && task.getActivityType() != ACTIVITY_TYPE_HOME + && task.getActivityType() != ACTIVITY_TYPE_RECENTS + && !mRecentTasks.isVisibleRecentTask(task)) { + // Skip if this task wouldn't be visibile (ever) from recents, with an exception for the + // home & recent tasks return; } diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 57d0a335a688..29a2e18f46a8 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -142,11 +142,13 @@ class WallpaperController { mFindResults.setUseTopWallpaperAsTarget(true); } - final boolean keyguardGoingAwayWithWallpaper = (w.mActivityRecord != null - && w.mActivityRecord.isAnimating(TRANSITION | PARENTS) - && AppTransition.isKeyguardGoingAwayTransit(w.mActivityRecord.getTransit()) - && (w.mActivityRecord.getTransitFlags() - & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0); + final WindowContainer animatingContainer = w.mActivityRecord != null + ? w.mActivityRecord.getAnimatingContainer() : null; + final boolean keyguardGoingAwayWithWallpaper = (animatingContainer != null + && animatingContainer.isAnimating(TRANSITION | PARENTS) + && AppTransition.isKeyguardGoingAwayTransit(animatingContainer.mTransit) + && (animatingContainer.mTransitFlags + & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0); boolean needsShowWhenLockedWallpaper = false; if ((w.mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0 @@ -166,8 +168,6 @@ class WallpaperController { final RecentsAnimationController recentsAnimationController = mService.getRecentsAnimationController(); - final WindowContainer animatingContainer = - w.mActivityRecord != null ? w.mActivityRecord.getAnimatingContainer() : null; final boolean animationWallpaper = animatingContainer != null && animatingContainer.getAnimation() != null && animatingContainer.getAnimation().getShowWallpaper(); diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 0cfdebc6792d..6b9fbcbf459f 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -157,9 +157,7 @@ class WindowSurfacePlacer { mInLayout = true; - boolean recoveringMemory = false; if (!mService.mForceRemoves.isEmpty()) { - recoveringMemory = true; // Wait a little bit for things to settle down, and off we go. while (!mService.mForceRemoves.isEmpty()) { final WindowState ws = mService.mForceRemoves.remove(0); @@ -177,7 +175,7 @@ class WindowSurfacePlacer { } try { - mService.mRoot.performSurfacePlacement(recoveringMemory); + mService.mRoot.performSurfacePlacement(); mInLayout = false; diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index 822f3835cc07..e4061b4fc34c 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -2068,8 +2068,8 @@ static void android_location_GnssLocationProvider_class_init_native(JNIEnv* env, class_gnssClock = (jclass) env->NewGlobalRef(gnssClockClass); method_gnssClockCtor = env->GetMethodID(class_gnssClock, "<init>", "()V"); - jclass gnssConfiguration_halInterfaceVersionClass = - env->FindClass("com/android/server/location/GnssConfiguration$HalInterfaceVersion"); + jclass gnssConfiguration_halInterfaceVersionClass = env->FindClass( + "com/android/server/location/gnss/GnssConfiguration$HalInterfaceVersion"); class_gnssConfiguration_halInterfaceVersion = (jclass) env->NewGlobalRef(gnssConfiguration_halInterfaceVersionClass); method_halInterfaceVersionCtor = @@ -3738,39 +3738,29 @@ static const JNINativeMethod sNetworkConnectivityMethods[] = { }; static const JNINativeMethod sConfigurationMethods[] = { - /* name, signature, funcPtr */ - {"native_get_gnss_configuration_version", - "()Lcom/android/server/location/GnssConfiguration$HalInterfaceVersion;", - reinterpret_cast<void *>( - android_location_GnssConfiguration_get_gnss_configuration_version)}, - {"native_set_supl_es", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_es)}, - {"native_set_supl_version", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_version)}, - {"native_set_supl_mode", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssConfiguration_set_supl_mode)}, - {"native_set_lpp_profile", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssConfiguration_set_lpp_profile)}, - {"native_set_gnss_pos_protocol_select", - "(I)Z", - reinterpret_cast<void *>( - android_location_GnssConfiguration_set_gnss_pos_protocol_select)}, - {"native_set_gps_lock", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssConfiguration_set_gps_lock)}, - {"native_set_emergency_supl_pdn", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssConfiguration_set_emergency_supl_pdn)}, - {"native_set_satellite_blacklist", - "([I[I)Z", - reinterpret_cast<void *>(android_location_GnssConfiguration_set_satellite_blacklist)}, - {"native_set_es_extension_sec", - "(I)Z", - reinterpret_cast<void *>(android_location_GnssConfiguration_set_es_extension_sec)}, + /* name, signature, funcPtr */ + {"native_get_gnss_configuration_version", + "()Lcom/android/server/location/gnss/GnssConfiguration$HalInterfaceVersion;", + reinterpret_cast<void*>( + android_location_GnssConfiguration_get_gnss_configuration_version)}, + {"native_set_supl_es", "(I)Z", + reinterpret_cast<void*>(android_location_GnssConfiguration_set_supl_es)}, + {"native_set_supl_version", "(I)Z", + reinterpret_cast<void*>(android_location_GnssConfiguration_set_supl_version)}, + {"native_set_supl_mode", "(I)Z", + reinterpret_cast<void*>(android_location_GnssConfiguration_set_supl_mode)}, + {"native_set_lpp_profile", "(I)Z", + reinterpret_cast<void*>(android_location_GnssConfiguration_set_lpp_profile)}, + {"native_set_gnss_pos_protocol_select", "(I)Z", + reinterpret_cast<void*>(android_location_GnssConfiguration_set_gnss_pos_protocol_select)}, + {"native_set_gps_lock", "(I)Z", + reinterpret_cast<void*>(android_location_GnssConfiguration_set_gps_lock)}, + {"native_set_emergency_supl_pdn", "(I)Z", + reinterpret_cast<void*>(android_location_GnssConfiguration_set_emergency_supl_pdn)}, + {"native_set_satellite_blacklist", "([I[I)Z", + reinterpret_cast<void*>(android_location_GnssConfiguration_set_satellite_blacklist)}, + {"native_set_es_extension_sec", "(I)Z", + reinterpret_cast<void*>(android_location_GnssConfiguration_set_es_extension_sec)}, }; static const JNINativeMethod sVisibilityControlMethods[] = { @@ -3782,53 +3772,27 @@ static const JNINativeMethod sVisibilityControlMethods[] = { }; int register_android_server_location_GnssLocationProvider(JNIEnv* env) { - jniRegisterNativeMethods(env, "com/android/server/location/GnssAntennaInfoProvider", + jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssAntennaInfoProvider", sAntennaInfoMethods, NELEM(sAntennaInfoMethods)); - jniRegisterNativeMethods( - env, - "com/android/server/location/GnssBatchingProvider", - sMethodsBatching, - NELEM(sMethodsBatching)); - jniRegisterNativeMethods( - env, - "com/android/server/location/GnssGeofenceProvider", - sGeofenceMethods, - NELEM(sGeofenceMethods)); - jniRegisterNativeMethods( - env, - "com/android/server/location/GnssMeasurementsProvider", - sMeasurementMethods, - NELEM(sMeasurementMethods)); - jniRegisterNativeMethods( - env, - "com/android/server/location/GnssMeasurementCorrectionsProvider", - sMeasurementCorrectionsMethods, - NELEM(sMeasurementCorrectionsMethods)); - jniRegisterNativeMethods( - env, - "com/android/server/location/GnssNavigationMessageProvider", - sNavigationMessageMethods, - NELEM(sNavigationMessageMethods)); - jniRegisterNativeMethods( - env, - "com/android/server/location/GnssNetworkConnectivityHandler", - sNetworkConnectivityMethods, - NELEM(sNetworkConnectivityMethods)); - jniRegisterNativeMethods( - env, - "com/android/server/location/GnssConfiguration", - sConfigurationMethods, - NELEM(sConfigurationMethods)); - jniRegisterNativeMethods( - env, - "com/android/server/location/GnssVisibilityControl", - sVisibilityControlMethods, - NELEM(sVisibilityControlMethods)); - return jniRegisterNativeMethods( - env, - "com/android/server/location/GnssLocationProvider", - sMethods, - NELEM(sMethods)); + jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssBatchingProvider", + sMethodsBatching, NELEM(sMethodsBatching)); + jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssGeofenceProvider", + sGeofenceMethods, NELEM(sGeofenceMethods)); + jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssMeasurementsProvider", + sMeasurementMethods, NELEM(sMeasurementMethods)); + jniRegisterNativeMethods(env, + "com/android/server/location/gnss/GnssMeasurementCorrectionsProvider", + sMeasurementCorrectionsMethods, NELEM(sMeasurementCorrectionsMethods)); + jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNavigationMessageProvider", + sNavigationMessageMethods, NELEM(sNavigationMessageMethods)); + jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssNetworkConnectivityHandler", + sNetworkConnectivityMethods, NELEM(sNetworkConnectivityMethods)); + jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssConfiguration", + sConfigurationMethods, NELEM(sConfigurationMethods)); + jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssVisibilityControl", + sVisibilityControlMethods, NELEM(sVisibilityControlMethods)); + return jniRegisterNativeMethods(env, "com/android/server/location/gnss/GnssLocationProvider", + sMethods, NELEM(sMethods)); } } /* namespace android */ diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index ed85b931c08e..ae27c7aabdda 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -286,7 +286,6 @@ void IncrementalService::onDump(int fd) { dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str()); dprintf(fd, "\t\t\tclassName: %s\n", params.className.c_str()); dprintf(fd, "\t\t\targuments: %s\n", params.arguments.c_str()); - dprintf(fd, "\t\t\tdynamicArgs: %d\n", int(params.dynamicArgs.size())); } dprintf(fd, "\t\tstorages (%d):\n", int(mnt.storages.size())); for (auto&& [storageId, storage] : mnt.storages) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b019e9dd03ba..c631eebe4a01 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -144,7 +144,6 @@ import com.android.server.power.ThermalManagerService; import com.android.server.recoverysystem.RecoverySystemService; import com.android.server.restrictions.RestrictionsManagerService; import com.android.server.role.RoleManagerService; -import com.android.server.rollback.RollbackManagerService; import com.android.server.security.FileIntegrityService; import com.android.server.security.KeyAttestationApplicationIdProviderService; import com.android.server.security.KeyChainSystemService; @@ -294,6 +293,8 @@ public final class SystemServer { "com.android.server.DeviceIdleController"; private static final String BLOB_STORE_MANAGER_SERVICE_CLASS = "com.android.server.blob.BlobStoreManagerService"; + private static final String ROLLBACK_MANAGER_SERVICE_CLASS = + "com.android.server.rollback.RollbackManagerService"; private static final String TETHERING_CONNECTOR_CLASS = "android.net.ITetheringConnector"; @@ -964,7 +965,7 @@ public final class SystemServer { // Manages apk rollbacks. t.traceBegin("StartRollbackManagerService"); - mSystemServiceManager.startService(RollbackManagerService.class); + mSystemServiceManager.startService(ROLLBACK_MANAGER_SERVICE_CLASS); t.traceEnd(); // Service to capture bugreports. diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java index ae8d5743668a..136ee91dd685 100644 --- a/services/people/java/com/android/server/people/data/DataManager.java +++ b/services/people/java/com/android/server/people/data/DataManager.java @@ -26,6 +26,7 @@ import android.app.NotificationManager; import android.app.Person; import android.app.prediction.AppTarget; import android.app.prediction.AppTargetEvent; +import android.app.usage.UsageEvents; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; @@ -70,6 +71,7 @@ import com.android.server.notification.NotificationManagerInternal; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -237,6 +239,27 @@ public class DataManager { eventHistory.addEvent(new Event(System.currentTimeMillis(), eventType)); } + /** + * Queries events for moving app to foreground between {@code startTime} and {@code endTime}. + */ + @NonNull + public List<UsageEvents.Event> queryAppMovingToForegroundEvents(@UserIdInt int callingUserId, + long startTime, long endTime) { + return UsageStatsQueryHelper.queryAppMovingToForegroundEvents(callingUserId, startTime, + endTime); + } + + /** + * Queries launch counts of apps within {@code packageNameFilter} between {@code startTime} + * and {@code endTime}. + */ + @NonNull + public Map<String, Integer> queryAppLaunchCount(@UserIdInt int callingUserId, long startTime, + long endTime, Set<String> packageNameFilter) { + return UsageStatsQueryHelper.queryAppLaunchCount(callingUserId, startTime, endTime, + packageNameFilter); + } + /** Prunes the data for the specified user. */ public void pruneDataForUser(@UserIdInt int userId, @NonNull CancellationSignal signal) { UserData userData = getUnlockedUserData(userId); @@ -382,7 +405,13 @@ public class DataManager { } } - private int mimeTypeToShareEventType(String mimeType) { + /** + * Converts {@code mimeType} to {@link Event.EventType}. + */ + public int mimeTypeToShareEventType(String mimeType) { + if (mimeType == null) { + return Event.TYPE_SHARE_OTHER; + } if (mimeType.startsWith("text/")) { return Event.TYPE_SHARE_TEXT; } else if (mimeType.startsWith("image/")) { diff --git a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java index 72f1abb70e34..6e6fea93c803 100644 --- a/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java +++ b/services/people/java/com/android/server/people/data/UsageStatsQueryHelper.java @@ -19,6 +19,8 @@ package com.android.server.people.data; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.usage.UsageEvents; +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; import android.app.usage.UsageStatsManagerInternal; import android.content.ComponentName; import android.content.LocusId; @@ -27,7 +29,10 @@ import android.util.ArrayMap; import com.android.server.LocalServices; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Function; /** A helper class that queries {@link UsageStatsManagerInternal}. */ @@ -46,7 +51,7 @@ class UsageStatsQueryHelper { */ UsageStatsQueryHelper(@UserIdInt int userId, Function<String, PackageData> packageDataGetter) { - mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class); + mUsageStatsManagerInternal = getUsageStatsManagerInternal(); mUserId = userId; mPackageDataGetter = packageDataGetter; } @@ -106,6 +111,53 @@ class UsageStatsQueryHelper { return mLastEventTimestamp; } + /** + * Queries {@link UsageStatsManagerInternal} events for moving app to foreground between + * {@code startTime} and {@code endTime}. + * + * @return a list containing events moving app to foreground. + */ + static List<UsageEvents.Event> queryAppMovingToForegroundEvents(@UserIdInt int userId, + long startTime, long endTime) { + List<UsageEvents.Event> res = new ArrayList<>(); + UsageEvents usageEvents = getUsageStatsManagerInternal().queryEventsForUser(userId, + startTime, endTime, + UsageEvents.HIDE_SHORTCUT_EVENTS | UsageEvents.HIDE_LOCUS_EVENTS); + if (usageEvents == null) { + return res; + } + while (usageEvents.hasNextEvent()) { + UsageEvents.Event e = new UsageEvents.Event(); + usageEvents.getNextEvent(e); + if (e.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED) { + res.add(e); + } + } + return res; + } + + /** + * Queries {@link UsageStatsManagerInternal} for launch count of apps within {@code + * packageNameFilter} between {@code startTime} and {@code endTime}.obfuscateInstantApps + * + * @return a map which keys are package names and values are app launch counts. + */ + static Map<String, Integer> queryAppLaunchCount(@UserIdInt int userId, long startTime, + long endTime, Set<String> packageNameFilter) { + List<UsageStats> stats = getUsageStatsManagerInternal().queryUsageStatsForUser(userId, + UsageStatsManager.INTERVAL_BEST, startTime, endTime, + /* obfuscateInstantApps= */ false); + Map<String, Integer> aggregatedStats = new ArrayMap<>(); + for (UsageStats stat : stats) { + String packageName = stat.getPackageName(); + if (packageNameFilter.contains(packageName)) { + aggregatedStats.put(packageName, + aggregatedStats.getOrDefault(packageName, 0) + stat.getAppLaunchCount()); + } + } + return aggregatedStats; + } + private void onInAppConversationEnded(@NonNull PackageData packageData, @NonNull UsageEvents.Event endEvent) { ComponentName activityName = @@ -138,4 +190,8 @@ class UsageStatsQueryHelper { EventStore.CATEGORY_LOCUS_ID_BASED, locusId.getId()); eventHistory.addEvent(event); } + + private static UsageStatsManagerInternal getUsageStatsManagerInternal() { + return LocalServices.getService(UsageStatsManagerInternal.class); + } } diff --git a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java index 8e5d75be12b7..d09d0b379769 100644 --- a/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java +++ b/services/people/java/com/android/server/people/prediction/ShareTargetPredictor.java @@ -27,13 +27,11 @@ import android.app.prediction.AppTargetId; import android.content.IntentFilter; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager.ShareShortcutInfo; -import android.util.Range; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ChooserActivity; import com.android.server.people.data.ConversationInfo; import com.android.server.people.data.DataManager; -import com.android.server.people.data.Event; import com.android.server.people.data.EventHistory; import com.android.server.people.data.PackageData; @@ -42,6 +40,9 @@ import java.util.Collections; import java.util.List; import java.util.function.Consumer; +/** + * Predictor that predicts the {@link AppTarget} the user is most likely to open on share sheet. + */ class ShareTargetPredictor extends AppTargetPredictor { private final IntentFilter mIntentFilter; @@ -66,7 +67,9 @@ class ShareTargetPredictor extends AppTargetPredictor { @Override void predictTargets() { List<ShareTarget> shareTargets = getDirectShareTargets(); - rankTargets(shareTargets); + SharesheetModelScorer.computeScore(shareTargets, getShareEventType(mIntentFilter), + System.currentTimeMillis()); + Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore())); List<AppTarget> res = new ArrayList<>(); for (int i = 0; i < Math.min(getPredictionContext().getPredictedTargetCount(), shareTargets.size()); i++) { @@ -80,36 +83,16 @@ class ShareTargetPredictor extends AppTargetPredictor { @Override void sortTargets(List<AppTarget> targets, Consumer<List<AppTarget>> callback) { List<ShareTarget> shareTargets = getAppShareTargets(targets); - rankTargets(shareTargets); + SharesheetModelScorer.computeScoreForAppShare(shareTargets, + getShareEventType(mIntentFilter), getPredictionContext().getPredictedTargetCount(), + System.currentTimeMillis(), getDataManager(), + mCallingUserId); + Collections.sort(shareTargets, (t1, t2) -> -Float.compare(t1.getScore(), t2.getScore())); List<AppTarget> appTargetList = new ArrayList<>(); shareTargets.forEach(t -> appTargetList.add(t.getAppTarget())); callback.accept(appTargetList); } - private void rankTargets(List<ShareTarget> shareTargets) { - // Rank targets based on recency of sharing history only for the moment. - // TODO: Take more factors into ranking, e.g. frequency, mime type, foreground app. - Collections.sort(shareTargets, (t1, t2) -> { - if (t1.getEventHistory() == null) { - return 1; - } - if (t2.getEventHistory() == null) { - return -1; - } - Range<Long> timeSlot1 = t1.getEventHistory().getEventIndex( - Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot(); - Range<Long> timeSlot2 = t2.getEventHistory().getEventIndex( - Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot(); - if (timeSlot1 == null) { - return 1; - } else if (timeSlot2 == null) { - return -1; - } else { - return -Long.compare(timeSlot1.getUpper(), timeSlot2.getUpper()); - } - }); - } - private List<ShareTarget> getDirectShareTargets() { List<ShareTarget> shareTargets = new ArrayList<>(); List<ShareShortcutInfo> shareShortcuts = @@ -153,6 +136,11 @@ class ShareTargetPredictor extends AppTargetPredictor { return shareTargets; } + private int getShareEventType(IntentFilter intentFilter) { + String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null; + return getDataManager().mimeTypeToShareEventType(mimeType); + } + @VisibleForTesting static class ShareTarget { @@ -162,13 +150,16 @@ class ShareTargetPredictor extends AppTargetPredictor { private final EventHistory mEventHistory; @Nullable private final ConversationInfo mConversationInfo; + private float mScore; - private ShareTarget(@NonNull AppTarget appTarget, + @VisibleForTesting + ShareTarget(@NonNull AppTarget appTarget, @Nullable EventHistory eventHistory, @Nullable ConversationInfo conversationInfo) { mAppTarget = appTarget; mEventHistory = eventHistory; mConversationInfo = conversationInfo; + mScore = 0f; } @NonNull @@ -188,5 +179,15 @@ class ShareTargetPredictor extends AppTargetPredictor { ConversationInfo getConversationInfo() { return mConversationInfo; } + + @VisibleForTesting + float getScore() { + return mScore; + } + + @VisibleForTesting + void setScore(float score) { + mScore = score; + } } } diff --git a/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java b/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java new file mode 100644 index 000000000000..0ac5724210da --- /dev/null +++ b/services/people/java/com/android/server/people/prediction/SharesheetModelScorer.java @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2020 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.people.prediction; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.app.usage.UsageEvents; +import android.util.ArrayMap; +import android.util.Pair; +import android.util.Range; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.app.ChooserActivity; +import com.android.server.people.data.DataManager; +import com.android.server.people.data.Event; + +import java.time.Duration; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.concurrent.TimeUnit; + +/** Ranking scorer for Sharesheet targets. */ +class SharesheetModelScorer { + + private static final String TAG = "SharesheetModelScorer"; + private static final boolean DEBUG = false; + private static final Integer RECENCY_SCORE_COUNT = 6; + private static final float RECENCY_INITIAL_BASE_SCORE = 0.4F; + private static final float RECENCY_SCORE_INITIAL_DECAY = 0.05F; + private static final float RECENCY_SCORE_SUBSEQUENT_DECAY = 0.02F; + private static final long ONE_MONTH_WINDOW = TimeUnit.DAYS.toMillis(30); + private static final long FOREGROUND_APP_PROMO_TIME_WINDOW = TimeUnit.MINUTES.toMillis(10); + private static final float FREQUENTLY_USED_APP_SCORE_DECAY = 0.9F; + @VisibleForTesting + static final float FOREGROUND_APP_WEIGHT = 0F; + @VisibleForTesting + static final String CHOOSER_ACTIVITY = ChooserActivity.class.getSimpleName(); + + // Keep constructor private to avoid class being instantiated. + private SharesheetModelScorer() { + } + + /** + * Computes each target's recency, frequency and frequency of the same {@code shareEventType} + * based on past sharing history. Update {@link ShareTargetPredictor.ShareTargetScore}. + */ + static void computeScore(List<ShareTargetPredictor.ShareTarget> shareTargets, + int shareEventType, long now) { + if (shareTargets.isEmpty()) { + return; + } + float totalFreqScore = 0f; + int freqScoreCount = 0; + float totalMimeFreqScore = 0f; + int mimeFreqScoreCount = 0; + // Top of this heap has lowest rank. + PriorityQueue<Pair<ShareTargetRankingScore, Range<Long>>> recencyMinHeap = + new PriorityQueue<>(RECENCY_SCORE_COUNT, + Comparator.comparingLong(p -> p.second.getUpper())); + List<ShareTargetRankingScore> scoreList = new ArrayList<>(shareTargets.size()); + for (ShareTargetPredictor.ShareTarget target : shareTargets) { + ShareTargetRankingScore shareTargetScore = new ShareTargetRankingScore(); + scoreList.add(shareTargetScore); + if (target.getEventHistory() == null) { + continue; + } + // Counts frequency + List<Range<Long>> timeSlots = target.getEventHistory().getEventIndex( + Event.SHARE_EVENT_TYPES).getActiveTimeSlots(); + if (!timeSlots.isEmpty()) { + for (Range<Long> timeSlot : timeSlots) { + shareTargetScore.incrementFrequencyScore( + getFreqDecayedOnElapsedTime(now - timeSlot.getLower())); + } + totalFreqScore += shareTargetScore.getFrequencyScore(); + freqScoreCount++; + } + // Counts frequency for sharing same mime type + List<Range<Long>> timeSlotsOfSameType = target.getEventHistory().getEventIndex( + shareEventType).getActiveTimeSlots(); + if (!timeSlotsOfSameType.isEmpty()) { + for (Range<Long> timeSlot : timeSlotsOfSameType) { + shareTargetScore.incrementMimeFrequencyScore( + getFreqDecayedOnElapsedTime(now - timeSlot.getLower())); + } + totalMimeFreqScore += shareTargetScore.getMimeFrequencyScore(); + mimeFreqScoreCount++; + } + // Records most recent targets + Range<Long> mostRecentTimeSlot = target.getEventHistory().getEventIndex( + Event.SHARE_EVENT_TYPES).getMostRecentActiveTimeSlot(); + if (mostRecentTimeSlot == null) { + continue; + } + if (recencyMinHeap.size() < RECENCY_SCORE_COUNT + || mostRecentTimeSlot.getUpper() > recencyMinHeap.peek().second.getUpper()) { + if (recencyMinHeap.size() == RECENCY_SCORE_COUNT) { + recencyMinHeap.poll(); + } + recencyMinHeap.offer(new Pair(shareTargetScore, mostRecentTimeSlot)); + } + } + // Calculates recency score + while (!recencyMinHeap.isEmpty()) { + float recencyScore = RECENCY_INITIAL_BASE_SCORE; + if (recencyMinHeap.size() > 1) { + recencyScore = RECENCY_INITIAL_BASE_SCORE - RECENCY_SCORE_INITIAL_DECAY + - RECENCY_SCORE_SUBSEQUENT_DECAY * (recencyMinHeap.size() - 2); + } + recencyMinHeap.poll().first.setRecencyScore(recencyScore); + } + + Float avgFreq = freqScoreCount != 0 ? totalFreqScore / freqScoreCount : 0f; + Float avgMimeFreq = mimeFreqScoreCount != 0 ? totalMimeFreqScore / mimeFreqScoreCount : 0f; + for (int i = 0; i < scoreList.size(); i++) { + ShareTargetPredictor.ShareTarget target = shareTargets.get(i); + ShareTargetRankingScore targetScore = scoreList.get(i); + // Normalizes freq and mimeFreq score + targetScore.setFrequencyScore(normalizeFreqScore( + avgFreq.equals(0f) ? 0f : targetScore.getFrequencyScore() / avgFreq)); + targetScore.setMimeFrequencyScore(normalizeMimeFreqScore(avgMimeFreq.equals(0f) ? 0f + : targetScore.getMimeFrequencyScore() / avgMimeFreq)); + // Calculates total score + targetScore.setTotalScore( + probOR(probOR(targetScore.getRecencyScore(), targetScore.getFrequencyScore()), + targetScore.getMimeFrequencyScore())); + target.setScore(targetScore.getTotalScore()); + + if (DEBUG) { + Slog.d(TAG, String.format( + "SharesheetModel: packageName: %s, className: %s, shortcutId: %s, " + + "recency:%.2f, freq_all:%.2f, freq_mime:%.2f, total:%.2f", + target.getAppTarget().getPackageName(), + target.getAppTarget().getClassName(), + target.getAppTarget().getShortcutInfo() != null + ? target.getAppTarget().getShortcutInfo().getId() : null, + targetScore.getRecencyScore(), + targetScore.getFrequencyScore(), + targetScore.getMimeFrequencyScore(), + targetScore.getTotalScore())); + } + } + } + + /** + * Computes ranking score for app sharing. Update {@link ShareTargetPredictor.ShareTargetScore}. + */ + static void computeScoreForAppShare(List<ShareTargetPredictor.ShareTarget> shareTargets, + int shareEventType, int targetsLimit, long now, @NonNull DataManager dataManager, + @UserIdInt int callingUserId) { + computeScore(shareTargets, shareEventType, now); + postProcess(shareTargets, targetsLimit, dataManager, callingUserId); + } + + private static void postProcess(List<ShareTargetPredictor.ShareTarget> shareTargets, + int targetsLimit, @NonNull DataManager dataManager, @UserIdInt int callingUserId) { + // Populates a map which key is package name and value is list of shareTargets descended + // on total score. + Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap = new ArrayMap<>(); + for (ShareTargetPredictor.ShareTarget shareTarget : shareTargets) { + String packageName = shareTarget.getAppTarget().getPackageName(); + shareTargetMap.computeIfAbsent(packageName, key -> new ArrayList<>()); + List<ShareTargetPredictor.ShareTarget> targetsList = shareTargetMap.get(packageName); + int index = 0; + while (index < targetsList.size()) { + if (shareTarget.getScore() > targetsList.get(index).getScore()) { + break; + } + index++; + } + targetsList.add(index, shareTarget); + } + promoteForegroundApp(shareTargetMap, dataManager, callingUserId); + promoteFrequentlyUsedApps(shareTargetMap, targetsLimit, dataManager, callingUserId); + } + + /** + * Promotes frequently used sharing apps, if recommended apps based on sharing history have not + * reached the limit (e.g. user did not share any content in last couple weeks) + */ + private static void promoteFrequentlyUsedApps( + Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap, int targetsLimit, + @NonNull DataManager dataManager, @UserIdInt int callingUserId) { + int validPredictionNum = 0; + float minValidScore = 1f; + for (List<ShareTargetPredictor.ShareTarget> targets : shareTargetMap.values()) { + for (ShareTargetPredictor.ShareTarget target : targets) { + if (target.getScore() > 0f) { + validPredictionNum++; + minValidScore = Math.min(target.getScore(), minValidScore); + } + } + } + // Skips if recommended apps based on sharing history have already reached the limit. + if (validPredictionNum >= targetsLimit) { + return; + } + long now = System.currentTimeMillis(); + Map<String, Integer> appLaunchCountsMap = dataManager.queryAppLaunchCount( + callingUserId, now - ONE_MONTH_WINDOW, now, shareTargetMap.keySet()); + List<Pair<String, Integer>> appLaunchCounts = new ArrayList<>(); + for (Map.Entry<String, Integer> entry : appLaunchCountsMap.entrySet()) { + if (entry.getValue() > 0) { + appLaunchCounts.add(new Pair(entry.getKey(), entry.getValue())); + } + } + Collections.sort(appLaunchCounts, (p1, p2) -> -Integer.compare(p1.second, p2.second)); + for (Pair<String, Integer> entry : appLaunchCounts) { + if (!shareTargetMap.containsKey(entry.first)) { + continue; + } + ShareTargetPredictor.ShareTarget target = shareTargetMap.get(entry.first).get(0); + if (target.getScore() > 0f) { + continue; + } + minValidScore *= FREQUENTLY_USED_APP_SCORE_DECAY; + target.setScore(minValidScore); + if (DEBUG) { + Slog.d(TAG, String.format( + "SharesheetModel: promoteFrequentUsedApps packageName: %s, className: %s," + + " total:%.2f", + target.getAppTarget().getPackageName(), + target.getAppTarget().getClassName(), + target.getScore())); + } + validPredictionNum++; + if (validPredictionNum == targetsLimit) { + return; + } + } + } + + /** + * Promotes the foreground app just prior to source sharing app. Share often occurs between + * two apps the user is switching. + */ + private static void promoteForegroundApp( + Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap, + @NonNull DataManager dataManager, @UserIdInt int callingUserId) { + String sharingForegroundApp = findSharingForegroundApp(shareTargetMap, dataManager, + callingUserId); + if (sharingForegroundApp != null) { + ShareTargetPredictor.ShareTarget target = shareTargetMap.get(sharingForegroundApp).get( + 0); + target.setScore(probOR(target.getScore(), FOREGROUND_APP_WEIGHT)); + if (DEBUG) { + Slog.d(TAG, String.format( + "SharesheetModel: promoteForegroundApp packageName: %s, className: %s, " + + "total:%.2f", + target.getAppTarget().getPackageName(), + target.getAppTarget().getClassName(), + target.getScore())); + } + } + } + + /** + * Find the foreground app just prior to source sharing app from usageStatsManager. Returns null + * if it is not available. + */ + @Nullable + private static String findSharingForegroundApp( + Map<String, List<ShareTargetPredictor.ShareTarget>> shareTargetMap, + @NonNull DataManager dataManager, @UserIdInt int callingUserId) { + String sharingForegroundApp = null; + long now = System.currentTimeMillis(); + List<UsageEvents.Event> events = dataManager.queryAppMovingToForegroundEvents( + callingUserId, now - FOREGROUND_APP_PROMO_TIME_WINDOW, now); + String sourceApp = null; + for (int i = events.size() - 1; i >= 0; i--) { + String className = events.get(i).getClassName(); + String packageName = events.get(i).getPackageName(); + if (packageName == null || (className != null && className.contains(CHOOSER_ACTIVITY)) + || packageName.contains(CHOOSER_ACTIVITY)) { + continue; + } + if (sourceApp == null) { + sourceApp = packageName; + } else if (!packageName.equals(sourceApp) && shareTargetMap.containsKey(packageName)) { + sharingForegroundApp = packageName; + break; + } + } + return sharingForegroundApp; + } + + /** + * Probabilistic OR (also known as the algebraic sum). If a <= 1 and b <= 1, the result will be + * <= 1.0. + */ + private static float probOR(float a, float b) { + return 1f - (1f - a) * (1f - b); + } + + /** Counts frequency of share targets. Decays frequency for old shares. */ + private static float getFreqDecayedOnElapsedTime(long elapsedTimeMillis) { + Duration duration = Duration.ofMillis(elapsedTimeMillis); + if (duration.compareTo(Duration.ofDays(1)) <= 0) { + return 1.0f; + } else if (duration.compareTo(Duration.ofDays(3)) <= 0) { + return 0.9f; + } else if (duration.compareTo(Duration.ofDays(7)) <= 0) { + return 0.8f; + } else if (duration.compareTo(Duration.ofDays(14)) <= 0) { + return 0.7f; + } else { + return 0.6f; + } + } + + /** Normalizes frequency score. */ + private static float normalizeFreqScore(double freqRatio) { + if (freqRatio >= 2.5) { + return 0.2f; + } else if (freqRatio >= 1.5) { + return 0.15f; + } else if (freqRatio >= 1.0) { + return 0.1f; + } else if (freqRatio >= 0.75) { + return 0.05f; + } else { + return 0f; + } + } + + /** Normalizes mimetype-specific frequency score. */ + private static float normalizeMimeFreqScore(double freqRatio) { + if (freqRatio >= 2.0) { + return 0.2f; + } else if (freqRatio >= 1.2) { + return 0.15f; + } else if (freqRatio > 0.0) { + return 0.1f; + } else { + return 0f; + } + } + + private static class ShareTargetRankingScore { + + private float mRecencyScore = 0f; + private float mFrequencyScore = 0f; + private float mMimeFrequencyScore = 0f; + private float mTotalScore = 0f; + + float getTotalScore() { + return mTotalScore; + } + + void setTotalScore(float totalScore) { + mTotalScore = totalScore; + } + + float getRecencyScore() { + return mRecencyScore; + } + + void setRecencyScore(float recencyScore) { + mRecencyScore = recencyScore; + } + + float getFrequencyScore() { + return mFrequencyScore; + } + + void setFrequencyScore(float frequencyScore) { + mFrequencyScore = frequencyScore; + } + + void incrementFrequencyScore(float incremental) { + mFrequencyScore += incremental; + } + + float getMimeFrequencyScore() { + return mMimeFrequencyScore; + } + + void setMimeFrequencyScore(float mimeFrequencyScore) { + mMimeFrequencyScore = mimeFrequencyScore; + } + + void incrementMimeFrequencyScore(float incremental) { + mMimeFrequencyScore += incremental; + } + } +} diff --git a/services/robotests/src/com/android/server/location/GnssAntennaInfoProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssAntennaInfoProviderTest.java index 76f7ad646bb1..d8acd6ea6948 100644 --- a/services/robotests/src/com/android/server/location/GnssAntennaInfoProviderTest.java +++ b/services/robotests/src/com/android/server/location/gnss/GnssAntennaInfoProviderTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.location; +package com.android.server.location.gnss; import static com.google.common.truth.Truth.assertThat; @@ -41,7 +41,8 @@ import org.robolectric.RuntimeEnvironment; @Presubmit public class GnssAntennaInfoProviderTest { @Mock - private GnssAntennaInfoProvider.GnssAntennaInfoProviderNative mMockNative; + private GnssAntennaInfoProvider.GnssAntennaInfoProviderNative + mMockNative; private GnssAntennaInfoProvider mTestProvider; /** Setup. */ diff --git a/services/robotests/src/com/android/server/location/GnssBatchingProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java index d58c3f73b8e8..25d6aa4dae29 100644 --- a/services/robotests/src/com/android/server/location/GnssBatchingProviderTest.java +++ b/services/robotests/src/com/android/server/location/gnss/GnssBatchingProviderTest.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import static com.google.common.truth.Truth.assertThat; @@ -11,7 +27,7 @@ import static org.mockito.Mockito.when; import android.platform.test.annotations.Presubmit; -import com.android.server.location.GnssBatchingProvider.GnssBatchingProviderNative; +import com.android.server.location.gnss.GnssBatchingProvider.GnssBatchingProviderNative; import org.junit.Before; import org.junit.Test; diff --git a/services/robotests/src/com/android/server/location/GnssGeofenceProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java index 30c73368da15..4a533aac01db 100644 --- a/services/robotests/src/com/android/server/location/GnssGeofenceProviderTest.java +++ b/services/robotests/src/com/android/server/location/gnss/GnssGeofenceProviderTest.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import static org.mockito.ArgumentMatchers.anyDouble; import static org.mockito.ArgumentMatchers.anyInt; diff --git a/services/robotests/src/com/android/server/location/GnssMeasurementsProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java index b349b67dab0c..e7d9ef810e51 100644 --- a/services/robotests/src/com/android/server/location/GnssMeasurementsProviderTest.java +++ b/services/robotests/src/com/android/server/location/gnss/GnssMeasurementsProviderTest.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import static com.google.common.truth.Truth.assertThat; @@ -26,7 +42,8 @@ import org.robolectric.RuntimeEnvironment; @Presubmit public class GnssMeasurementsProviderTest { @Mock - private GnssMeasurementsProvider.GnssMeasurementProviderNative mMockNative; + private GnssMeasurementsProvider.GnssMeasurementProviderNative + mMockNative; private GnssMeasurementsProvider mTestProvider; @Before diff --git a/services/robotests/src/com/android/server/location/GnssNavigationMessageProviderTest.java b/services/robotests/src/com/android/server/location/gnss/GnssNavigationMessageProviderTest.java index aa2a96e6fad4..c21db73fb56c 100644 --- a/services/robotests/src/com/android/server/location/GnssNavigationMessageProviderTest.java +++ b/services/robotests/src/com/android/server/location/gnss/GnssNavigationMessageProviderTest.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import static com.google.common.truth.Truth.assertThat; @@ -25,7 +41,8 @@ import org.robolectric.RuntimeEnvironment; @Presubmit public class GnssNavigationMessageProviderTest { @Mock - private GnssNavigationMessageProvider.GnssNavigationMessageProviderNative mMockNative; + private GnssNavigationMessageProvider.GnssNavigationMessageProviderNative + mMockNative; private GnssNavigationMessageProvider mTestProvider; @Before diff --git a/services/robotests/src/com/android/server/location/GnssPositionModeTest.java b/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java index f37f50e76ae5..7117ff95b401 100644 --- a/services/robotests/src/com/android/server/location/GnssPositionModeTest.java +++ b/services/robotests/src/com/android/server/location/gnss/GnssPositionModeTest.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import static com.google.common.truth.Truth.assertThat; diff --git a/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java b/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java index ba4a753e4813..7c73a2f92f71 100644 --- a/services/robotests/src/com/android/server/location/GnssSatelliteBlacklistHelperTest.java +++ b/services/robotests/src/com/android/server/location/gnss/GnssSatelliteBlacklistHelperTest.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import static com.google.common.truth.Truth.assertThat; @@ -35,7 +51,8 @@ public class GnssSatelliteBlacklistHelperTest { private ContentResolver mContentResolver; @Mock - private GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback mCallback; + private GnssSatelliteBlacklistHelper.GnssSatelliteBlacklistCallback + mCallback; @Before public void setUp() { diff --git a/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java b/services/robotests/src/com/android/server/location/gnss/NtpTimeHelperTest.java index 9c5d4ad6ceeb..9b59aaddc4d4 100644 --- a/services/robotests/src/com/android/server/location/NtpTimeHelperTest.java +++ b/services/robotests/src/com/android/server/location/gnss/NtpTimeHelperTest.java @@ -1,4 +1,20 @@ -package com.android.server.location; +/* + * Copyright (C) 2020 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.location.gnss; import static com.google.common.truth.Truth.assertThat; @@ -10,7 +26,7 @@ import android.os.SystemClock; import android.platform.test.annotations.Presubmit; import android.util.NtpTrustedTime; -import com.android.server.location.NtpTimeHelper.InjectNtpTimeCallback; +import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback; import org.junit.Before; import org.junit.Test; diff --git a/services/tests/servicestests/src/com/android/server/MountServiceTests.java b/services/tests/servicestests/src/com/android/server/MountServiceTests.java deleted file mode 100644 index b1b31744c88b..000000000000 --- a/services/tests/servicestests/src/com/android/server/MountServiceTests.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.Resources.NotFoundException; -import android.os.FileUtils; -import android.os.storage.OnObbStateChangeListener; -import android.os.storage.StorageManager; -import android.test.AndroidTestCase; -import android.test.ComparisonFailure; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -import com.android.frameworks.servicestests.R; - -import java.io.File; -import java.io.InputStream; - -public class MountServiceTests extends AndroidTestCase { - private static final String TAG = "MountServiceTests"; - - private static final long MAX_WAIT_TIME = 25*1000; - private static final long WAIT_TIME_INCR = 5*1000; - - private static final String OBB_MOUNT_PREFIX = "/mnt/obb/"; - - private static void assertStartsWith(String message, String prefix, String actual) { - if (!actual.startsWith(prefix)) { - throw new ComparisonFailure(message, prefix, actual); - } - } - - private static class ObbObserver extends OnObbStateChangeListener { - private String path; - - public int state = -1; - boolean done = false; - - @Override - public void onObbStateChange(String path, int state) { - Log.d(TAG, "Received message. path=" + path + ", state=" + state); - synchronized (this) { - this.path = path; - this.state = state; - done = true; - notifyAll(); - } - } - - public String getPath() { - assertTrue("Expected ObbObserver to have received a state change.", done); - return path; - } - - public int getState() { - assertTrue("Expected ObbObserver to have received a state change.", done); - return state; - } - - public void reset() { - this.path = null; - this.state = -1; - done = false; - } - - public boolean isDone() { - return done; - } - - public boolean waitForCompletion() { - long waitTime = 0; - synchronized (this) { - while (!isDone() && waitTime < MAX_WAIT_TIME) { - try { - wait(WAIT_TIME_INCR); - waitTime += WAIT_TIME_INCR; - } catch (InterruptedException e) { - Log.i(TAG, "Interrupted during sleep", e); - } - } - } - - return isDone(); - } - } - - private File getFilePath(String name) { - final File filesDir = mContext.getFilesDir(); - final File outFile = new File(filesDir, name); - return outFile; - } - - private void copyRawToFile(int rawResId, File outFile) { - Resources res = mContext.getResources(); - InputStream is = null; - try { - is = res.openRawResource(rawResId); - } catch (NotFoundException e) { - fail("Failed to load resource with id: " + rawResId); - } - FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG - | FileUtils.S_IRWXO, -1, -1); - assertTrue(FileUtils.copyToFile(is, outFile)); - FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG - | FileUtils.S_IRWXO, -1, -1); - } - - private StorageManager getStorageManager() { - return (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE); - } - - private void mountObb(StorageManager sm, final int resource, final File file, - int expectedState) { - copyRawToFile(resource, file); - - final ObbObserver observer = new ObbObserver(); - assertTrue("mountObb call on " + file.getPath() + " should succeed", - sm.mountObb(file.getPath(), null, observer)); - - assertTrue("Mount should have completed", - observer.waitForCompletion()); - - if (expectedState == OnObbStateChangeListener.MOUNTED) { - assertTrue("OBB should be mounted", sm.isObbMounted(file.getPath())); - } - - assertEquals("Actual file and resolved file should be the same", - file.getPath(), observer.getPath()); - - assertEquals(expectedState, observer.getState()); - } - - private ObbObserver mountObbWithoutWait(final StorageManager sm, final int resource, - final File file) { - copyRawToFile(resource, file); - - final ObbObserver observer = new ObbObserver(); - assertTrue("mountObb call on " + file.getPath() + " should succeed", sm.mountObb(file - .getPath(), null, observer)); - - return observer; - } - - private void waitForObbActionCompletion(final StorageManager sm, final File file, - final ObbObserver observer, int expectedState, boolean checkPath) { - assertTrue("Mount should have completed", observer.waitForCompletion()); - - assertTrue("OBB should be mounted", sm.isObbMounted(file.getPath())); - - if (checkPath) { - assertEquals("Actual file and resolved file should be the same", file.getPath(), - observer.getPath()); - } - - assertEquals(expectedState, observer.getState()); - } - - private String checkMountedPath(final StorageManager sm, final File file) { - final String mountPath = sm.getMountedObbPath(file.getPath()); - assertStartsWith("Path should be in " + OBB_MOUNT_PREFIX, - OBB_MOUNT_PREFIX, - mountPath); - return mountPath; - } - - private void unmountObb(final StorageManager sm, final File file, int expectedState) { - final ObbObserver observer = new ObbObserver(); - - assertTrue("unmountObb call on test1.obb should succeed", - sm.unmountObb(file.getPath(), false, observer)); - - assertTrue("Unmount should have completed", - observer.waitForCompletion()); - - assertEquals(expectedState, observer.getState()); - - if (expectedState == OnObbStateChangeListener.UNMOUNTED) { - assertFalse("OBB should not be mounted", sm.isObbMounted(file.getPath())); - } - } - - @LargeTest - public void testMountAndUnmountObbNormal() { - StorageManager sm = getStorageManager(); - - final File outFile = getFilePath("test1.obb"); - - mountObb(sm, R.raw.test1, outFile, OnObbStateChangeListener.MOUNTED); - - mountObb(sm, R.raw.test1, outFile, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); - - final String mountPath = checkMountedPath(sm, outFile); - final File mountDir = new File(mountPath); - - assertTrue("OBB mounted path should be a directory", - mountDir.isDirectory()); - - unmountObb(sm, outFile, OnObbStateChangeListener.UNMOUNTED); - } - - @LargeTest - public void testAttemptMountNonObb() { - StorageManager sm = getStorageManager(); - - final File outFile = getFilePath("test1_nosig.obb"); - - try { - mountObb(sm, R.raw.test1_nosig, outFile, OnObbStateChangeListener.ERROR_INTERNAL); - fail("mountObb should've failed with an exception"); - } catch (IllegalArgumentException e) { - // Expected - } - - assertFalse("OBB should not be mounted", - sm.isObbMounted(outFile.getPath())); - - assertNull("OBB's mounted path should be null", - sm.getMountedObbPath(outFile.getPath())); - } - - @LargeTest - public void testAttemptMountObbWrongPackage() { - StorageManager sm = getStorageManager(); - - final File outFile = getFilePath("test1_wrongpackage.obb"); - - mountObb(sm, R.raw.test1_wrongpackage, outFile, - OnObbStateChangeListener.ERROR_PERMISSION_DENIED); - - assertFalse("OBB should not be mounted", - sm.isObbMounted(outFile.getPath())); - - assertNull("OBB's mounted path should be null", - sm.getMountedObbPath(outFile.getPath())); - } - - @LargeTest - public void testMountAndUnmountTwoObbs() { - StorageManager sm = getStorageManager(); - - final File file1 = getFilePath("test1.obb"); - final File file2 = getFilePath("test2.obb"); - - ObbObserver oo1 = mountObbWithoutWait(sm, R.raw.test1, file1); - ObbObserver oo2 = mountObbWithoutWait(sm, R.raw.test1, file2); - - Log.d(TAG, "Waiting for OBB #1 to complete mount"); - waitForObbActionCompletion(sm, file1, oo1, OnObbStateChangeListener.MOUNTED, false); - Log.d(TAG, "Waiting for OBB #2 to complete mount"); - waitForObbActionCompletion(sm, file2, oo2, OnObbStateChangeListener.MOUNTED, false); - - final String mountPath1 = checkMountedPath(sm, file1); - final File mountDir1 = new File(mountPath1); - assertTrue("OBB mounted path should be a directory", mountDir1.isDirectory()); - - final String mountPath2 = checkMountedPath(sm, file2); - final File mountDir2 = new File(mountPath2); - assertTrue("OBB mounted path should be a directory", mountDir2.isDirectory()); - - unmountObb(sm, file1, OnObbStateChangeListener.UNMOUNTED); - unmountObb(sm, file2, OnObbStateChangeListener.UNMOUNTED); - } -} diff --git a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java index a99c982753c5..be2a5c529181 100644 --- a/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/location/gnss/GnssManagerServiceTest.java @@ -61,17 +61,9 @@ import android.os.RemoteException; import com.android.server.LocalServices; import com.android.server.location.AppForegroundHelper; -import com.android.server.location.GnssAntennaInfoProvider; -import com.android.server.location.GnssAntennaInfoProvider.GnssAntennaInfoProviderNative; -import com.android.server.location.GnssBatchingProvider; -import com.android.server.location.GnssCapabilitiesProvider; -import com.android.server.location.GnssLocationProvider; -import com.android.server.location.GnssMeasurementCorrectionsProvider; -import com.android.server.location.GnssMeasurementsProvider; -import com.android.server.location.GnssMeasurementsProvider.GnssMeasurementProviderNative; -import com.android.server.location.GnssNavigationMessageProvider; -import com.android.server.location.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative; -import com.android.server.location.GnssStatusListenerHelper; +import com.android.server.location.gnss.GnssAntennaInfoProvider.GnssAntennaInfoProviderNative; +import com.android.server.location.gnss.GnssMeasurementsProvider.GnssMeasurementProviderNative; +import com.android.server.location.gnss.GnssNavigationMessageProvider.GnssNavigationMessageProviderNative; import com.android.server.location.LocationUsageLogger; import com.android.server.location.SettingsHelper; diff --git a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java index 7934d33f907d..03d9ad51e6c5 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/UsageStatsQueryHelperTest.java @@ -21,15 +21,16 @@ import static com.android.server.people.data.TestUtils.timestamp; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.usage.UsageEvents; +import android.app.usage.UsageStats; import android.app.usage.UsageStatsManagerInternal; import android.content.Context; import android.content.LocusId; @@ -50,6 +51,7 @@ import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.function.Predicate; @@ -58,7 +60,8 @@ import java.util.function.Predicate; public final class UsageStatsQueryHelperTest { private static final int USER_ID_PRIMARY = 0; - private static final String PKG_NAME = "pkg"; + private static final String PKG_NAME_1 = "pkg_1"; + private static final String PKG_NAME_2 = "pkg_2"; private static final String ACTIVITY_NAME = "TestActivity"; private static final String SHORTCUT_ID = "abc"; private static final LocusId LOCUS_ID_1 = new LocusId("locus_1"); @@ -80,7 +83,7 @@ public final class UsageStatsQueryHelperTest { File testDir = new File(ctx.getCacheDir(), "testdir"); ScheduledExecutorService scheduledExecutorService = new MockScheduledExecutorService(); - mPackageData = new TestPackageData(PKG_NAME, USER_ID_PRIMARY, pkg -> false, pkg -> false, + mPackageData = new TestPackageData(PKG_NAME_1, USER_ID_PRIMARY, pkg -> false, pkg -> false, scheduledExecutorService, testDir); mPackageData.mConversationStore.mConversationInfo = new ConversationInfo.Builder() .setShortcutId(SHORTCUT_ID) @@ -173,10 +176,72 @@ public final class UsageStatsQueryHelperTest { assertEquals(createInAppConversationEvent(130_000L, 30), events.get(2)); } + @Test + public void testQueryAppMovingToForegroundEvents() { + addUsageEvents( + createShortcutInvocationEvent(100_000L), + createActivityResumedEvent(110_000L), + createActivityStoppedEvent(120_000L), + createActivityResumedEvent(130_000L)); + + List<UsageEvents.Event> events = mHelper.queryAppMovingToForegroundEvents(USER_ID_PRIMARY, + 90_000L, + 200_000L); + + assertEquals(2, events.size()); + assertEquals(UsageEvents.Event.ACTIVITY_RESUMED, events.get(0).getEventType()); + assertEquals(110_000L, events.get(0).getTimeStamp()); + assertEquals(UsageEvents.Event.ACTIVITY_RESUMED, events.get(1).getEventType()); + assertEquals(130_000L, events.get(1).getTimeStamp()); + } + + @Test + public void testQueryAppLaunchCount() { + + UsageStats packageStats1 = createUsageStats(PKG_NAME_1, 2); + UsageStats packageStats2 = createUsageStats(PKG_NAME_1, 3); + UsageStats packageStats3 = createUsageStats(PKG_NAME_2, 1); + when(mUsageStatsManagerInternal.queryUsageStatsForUser(anyInt(), anyInt(), anyLong(), + anyLong(), anyBoolean())).thenReturn( + List.of(packageStats1, packageStats2, packageStats3)); + + Map<String, Integer> appLaunchCounts = mHelper.queryAppLaunchCount(USER_ID_PRIMARY, 90_000L, + 200_000L, Set.of(PKG_NAME_1, PKG_NAME_2)); + + assertEquals(2, appLaunchCounts.size()); + assertEquals(5, (long) appLaunchCounts.get(PKG_NAME_1)); + assertEquals(1, (long) appLaunchCounts.get(PKG_NAME_2)); + } + + @Test + public void testQueryAppLaunchCount_packageNameFiltered() { + + UsageStats packageStats1 = createUsageStats(PKG_NAME_1, 2); + UsageStats packageStats2 = createUsageStats(PKG_NAME_1, 3); + UsageStats packageStats3 = createUsageStats(PKG_NAME_2, 1); + when(mUsageStatsManagerInternal.queryUsageStatsForUser(anyInt(), anyInt(), anyLong(), + anyLong(), anyBoolean())).thenReturn( + List.of(packageStats1, packageStats2, packageStats3)); + + Map<String, Integer> appLaunchCounts = mHelper.queryAppLaunchCount(USER_ID_PRIMARY, 90_000L, + 200_000L, + Set.of(PKG_NAME_1)); + + assertEquals(1, appLaunchCounts.size()); + assertEquals(5, (long) appLaunchCounts.get(PKG_NAME_1)); + } + private void addUsageEvents(UsageEvents.Event... events) { UsageEvents usageEvents = new UsageEvents(Arrays.asList(events), new String[]{}); when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(), - eq(UsageEvents.SHOW_ALL_EVENT_DATA))).thenReturn(usageEvents); + anyInt())).thenReturn(usageEvents); + } + + private static UsageStats createUsageStats(String packageName, int launchCount) { + UsageStats packageStats = new UsageStats(); + packageStats.mPackageName = packageName; + packageStats.mAppLaunchCount = launchCount; + return packageStats; } private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { @@ -203,9 +268,15 @@ public final class UsageStatsQueryHelperTest { return e; } + private static UsageEvents.Event createActivityResumedEvent(long timestamp) { + UsageEvents.Event e = createUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, timestamp); + e.mClass = ACTIVITY_NAME; + return e; + } + private static UsageEvents.Event createUsageEvent(int eventType, long timestamp) { UsageEvents.Event e = new UsageEvents.Event(eventType, timestamp); - e.mPackage = PKG_NAME; + e.mPackage = PKG_NAME_1; return e; } diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java index c6cd34732acf..1480627b9b9f 100644 --- a/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java +++ b/services/tests/servicestests/src/com/android/server/people/prediction/ShareTargetPredictorTest.java @@ -127,6 +127,9 @@ public final class ShareTargetPredictorTest { when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1); when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2); when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3); + when(mEventHistory1.getEventIndex(anyInt())).thenReturn(mEventIndex1); + when(mEventHistory2.getEventIndex(anyInt())).thenReturn(mEventIndex2); + when(mEventHistory3.getEventIndex(anyInt())).thenReturn(mEventIndex3); when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L)); when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L)); when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L)); @@ -183,6 +186,12 @@ public final class ShareTargetPredictorTest { when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4); when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5); when(mEventHistory6.getEventIndex(anySet())).thenReturn(mEventIndex6); + when(mEventHistory1.getEventIndex(anyInt())).thenReturn(mEventIndex1); + when(mEventHistory2.getEventIndex(anyInt())).thenReturn(mEventIndex2); + when(mEventHistory3.getEventIndex(anyInt())).thenReturn(mEventIndex3); + when(mEventHistory4.getEventIndex(anyInt())).thenReturn(mEventIndex4); + when(mEventHistory5.getEventIndex(anyInt())).thenReturn(mEventIndex5); + when(mEventHistory6.getEventIndex(anyInt())).thenReturn(mEventIndex6); when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L)); when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L)); when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L)); @@ -220,19 +229,19 @@ public final class ShareTargetPredictorTest { @Test public void testSortTargets() { AppTarget appTarget1 = new AppTarget.Builder( - new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID)) + new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID)) .setClassName(CLASS_1) .build(); AppTarget appTarget2 = new AppTarget.Builder( - new AppTargetId("cls2#pkg1"), PACKAGE_1, UserHandle.of(USER_ID)) + new AppTargetId("cls2#pkg1"), PACKAGE_1, UserHandle.of(USER_ID)) .setClassName(CLASS_2) .build(); AppTarget appTarget3 = new AppTarget.Builder( - new AppTargetId("cls1#pkg2"), PACKAGE_2, UserHandle.of(USER_ID)) + new AppTargetId("cls1#pkg2"), PACKAGE_2, UserHandle.of(USER_ID)) .setClassName(CLASS_1) .build(); AppTarget appTarget4 = new AppTarget.Builder( - new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID)) + new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID)) .setClassName(CLASS_2) .build(); AppTarget appTarget5 = new AppTarget.Builder( @@ -251,6 +260,10 @@ public final class ShareTargetPredictorTest { when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2); when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3); when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4); + when(mEventHistory1.getEventIndex(anyInt())).thenReturn(mEventIndex1); + when(mEventHistory2.getEventIndex(anyInt())).thenReturn(mEventIndex2); + when(mEventHistory3.getEventIndex(anyInt())).thenReturn(mEventIndex3); + when(mEventHistory4.getEventIndex(anyInt())).thenReturn(mEventIndex4); when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(1L, 2L)); when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(2L, 3L)); when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(new Range<>(3L, 4L)); @@ -265,14 +278,14 @@ public final class ShareTargetPredictorTest { appTarget4, appTarget3, appTarget2, appTarget1, appTarget5); } - private ShareShortcutInfo buildShareShortcut( + private static ShareShortcutInfo buildShareShortcut( String packageName, String className, String shortcutId) { ShortcutInfo shortcutInfo = buildShortcut(packageName, shortcutId); ComponentName componentName = new ComponentName(packageName, className); return new ShareShortcutInfo(shortcutInfo, componentName); } - private ShortcutInfo buildShortcut(String packageName, String shortcutId) { + private static ShortcutInfo buildShortcut(String packageName, String shortcutId) { Context mockContext = mock(Context.class); when(mockContext.getPackageName()).thenReturn(packageName); when(mockContext.getUserId()).thenReturn(USER_ID); diff --git a/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java b/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java new file mode 100644 index 000000000000..9d96d6b7d861 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/people/prediction/SharesheetModelScorerTest.java @@ -0,0 +1,406 @@ +/* + * Copyright (C) 2020 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.people.prediction; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anySet; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.prediction.AppTarget; +import android.app.prediction.AppTargetId; +import android.app.usage.UsageEvents; +import android.os.UserHandle; +import android.util.Range; + +import com.android.server.people.data.DataManager; +import com.android.server.people.data.Event; +import com.android.server.people.data.EventHistory; +import com.android.server.people.data.EventIndex; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.time.Duration; +import java.util.List; +import java.util.Map; + +@RunWith(JUnit4.class) +public final class SharesheetModelScorerTest { + + private static final int USER_ID = 0; + private static final String PACKAGE_1 = "pkg1"; + private static final String PACKAGE_2 = "pkg2"; + private static final String PACKAGE_3 = "pkg3"; + private static final String CLASS_1 = "cls1"; + private static final String CLASS_2 = "cls2"; + private static final double DELTA = 1e-6; + private static final long NOW = System.currentTimeMillis(); + private static final Range<Long> WITHIN_ONE_DAY = new Range( + NOW - Duration.ofHours(23).toMillis(), + NOW - Duration.ofHours(22).toMillis()); + private static final Range<Long> TWO_DAYS_AGO = new Range( + NOW - Duration.ofHours(50).toMillis(), + NOW - Duration.ofHours(49).toMillis()); + private static final Range<Long> FIVE_DAYS_AGO = new Range( + NOW - Duration.ofDays(6).toMillis(), + NOW - Duration.ofDays(5).toMillis()); + private static final Range<Long> EIGHT_DAYS_AGO = new Range( + NOW - Duration.ofDays(9).toMillis(), + NOW - Duration.ofDays(8).toMillis()); + private static final Range<Long> TWELVE_DAYS_AGO = new Range( + NOW - Duration.ofDays(13).toMillis(), + NOW - Duration.ofDays(12).toMillis()); + private static final Range<Long> TWENTY_DAYS_AGO = new Range( + NOW - Duration.ofDays(21).toMillis(), + NOW - Duration.ofDays(20).toMillis()); + private static final Range<Long> FOUR_WEEKS_AGO = new Range( + NOW - Duration.ofDays(29).toMillis(), + NOW - Duration.ofDays(28).toMillis()); + + @Mock + private DataManager mDataManager; + @Mock + private EventHistory mEventHistory1; + @Mock + private EventHistory mEventHistory2; + @Mock + private EventHistory mEventHistory3; + @Mock + private EventHistory mEventHistory4; + @Mock + private EventHistory mEventHistory5; + @Mock + private EventIndex mEventIndex1; + @Mock + private EventIndex mEventIndex2; + @Mock + private EventIndex mEventIndex3; + @Mock + private EventIndex mEventIndex4; + @Mock + private EventIndex mEventIndex5; + @Mock + private EventIndex mEventIndex6; + @Mock + private EventIndex mEventIndex7; + @Mock + private EventIndex mEventIndex8; + @Mock + private EventIndex mEventIndex9; + @Mock + private EventIndex mEventIndex10; + + private ShareTargetPredictor.ShareTarget mShareTarget1; + private ShareTargetPredictor.ShareTarget mShareTarget2; + private ShareTargetPredictor.ShareTarget mShareTarget3; + private ShareTargetPredictor.ShareTarget mShareTarget4; + private ShareTargetPredictor.ShareTarget mShareTarget5; + private ShareTargetPredictor.ShareTarget mShareTarget6; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mShareTarget1 = new ShareTargetPredictor.ShareTarget( + new AppTarget.Builder( + new AppTargetId("cls1#pkg1"), PACKAGE_1, UserHandle.of(USER_ID)) + .setClassName(CLASS_1).build(), + mEventHistory1, null); + mShareTarget2 = new ShareTargetPredictor.ShareTarget( + new AppTarget.Builder(new AppTargetId("cls2#pkg1"), PACKAGE_1, + UserHandle.of(USER_ID)).setClassName(CLASS_2).build(), + mEventHistory2, null); + mShareTarget3 = new ShareTargetPredictor.ShareTarget( + new AppTarget.Builder( + new AppTargetId("cls1#pkg2"), PACKAGE_2, UserHandle.of(USER_ID)) + .setClassName(CLASS_1).build(), + mEventHistory3, null); + mShareTarget4 = new ShareTargetPredictor.ShareTarget( + new AppTarget.Builder( + new AppTargetId("cls2#pkg2"), PACKAGE_2, UserHandle.of(USER_ID)) + .setClassName(CLASS_2).build(), + mEventHistory4, null); + mShareTarget5 = new ShareTargetPredictor.ShareTarget( + new AppTarget.Builder( + new AppTargetId("cls1#pkg3"), PACKAGE_3, UserHandle.of(USER_ID)) + .setClassName(CLASS_1).build(), + mEventHistory5, null); + mShareTarget6 = new ShareTargetPredictor.ShareTarget( + new AppTarget.Builder( + new AppTargetId("cls2#pkg3"), PACKAGE_3, UserHandle.of(USER_ID)) + .setClassName(CLASS_2).build(), + null, null); + } + + @Test + public void testComputeScore() { + // Frequency and recency + when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1); + when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2); + when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3); + when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4); + when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5); + + when(mEventIndex1.getActiveTimeSlots()).thenReturn( + List.of(WITHIN_ONE_DAY, TWO_DAYS_AGO, FIVE_DAYS_AGO)); + when(mEventIndex2.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO)); + when(mEventIndex3.getActiveTimeSlots()).thenReturn(List.of(FIVE_DAYS_AGO, TWENTY_DAYS_AGO)); + when(mEventIndex4.getActiveTimeSlots()).thenReturn( + List.of(EIGHT_DAYS_AGO, TWELVE_DAYS_AGO, FOUR_WEEKS_AGO)); + when(mEventIndex5.getActiveTimeSlots()).thenReturn(List.of()); + + when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(WITHIN_ONE_DAY); + when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(TWO_DAYS_AGO); + when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(FIVE_DAYS_AGO); + when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(EIGHT_DAYS_AGO); + when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(null); + + // Frequency of the same mime type + when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6); + when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7); + when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8); + when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9); + when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10); + + when(mEventIndex6.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO)); + when(mEventIndex7.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO)); + when(mEventIndex8.getActiveTimeSlots()).thenReturn(List.of()); + when(mEventIndex9.getActiveTimeSlots()).thenReturn(List.of(EIGHT_DAYS_AGO)); + when(mEventIndex10.getActiveTimeSlots()).thenReturn(List.of()); + + SharesheetModelScorer.computeScore( + List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5, + mShareTarget6), + Event.TYPE_SHARE_TEXT, + NOW); + + // Verification + assertEquals(0.514f, mShareTarget1.getScore(), DELTA); + assertEquals(0.475125f, mShareTarget2.getScore(), DELTA); + assertEquals(0.33f, mShareTarget3.getScore(), DELTA); + assertEquals(0.4411f, mShareTarget4.getScore(), DELTA); + assertEquals(0f, mShareTarget5.getScore(), DELTA); + assertEquals(0f, mShareTarget6.getScore(), DELTA); + } + + @Test + public void testComputeScoreForAppShare() { + // Frequency and recency + when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1); + when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2); + when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3); + when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4); + when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5); + + when(mEventIndex1.getActiveTimeSlots()).thenReturn( + List.of(WITHIN_ONE_DAY, TWO_DAYS_AGO, FIVE_DAYS_AGO)); + when(mEventIndex2.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO)); + when(mEventIndex3.getActiveTimeSlots()).thenReturn(List.of(FIVE_DAYS_AGO, TWENTY_DAYS_AGO)); + when(mEventIndex4.getActiveTimeSlots()).thenReturn( + List.of(EIGHT_DAYS_AGO, TWELVE_DAYS_AGO, FOUR_WEEKS_AGO)); + when(mEventIndex5.getActiveTimeSlots()).thenReturn(List.of()); + + when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(WITHIN_ONE_DAY); + when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(TWO_DAYS_AGO); + when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(FIVE_DAYS_AGO); + when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(EIGHT_DAYS_AGO); + when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(null); + + // Frequency of the same mime type + when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6); + when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7); + when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8); + when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9); + when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10); + + when(mEventIndex6.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO)); + when(mEventIndex7.getActiveTimeSlots()).thenReturn(List.of(TWO_DAYS_AGO, TWELVE_DAYS_AGO)); + when(mEventIndex8.getActiveTimeSlots()).thenReturn(List.of()); + when(mEventIndex9.getActiveTimeSlots()).thenReturn(List.of(EIGHT_DAYS_AGO)); + when(mEventIndex10.getActiveTimeSlots()).thenReturn(List.of()); + + SharesheetModelScorer.computeScoreForAppShare( + List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5, + mShareTarget6), + Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID); + + // Verification + assertEquals(0.514f, mShareTarget1.getScore(), DELTA); + assertEquals(0.475125f, mShareTarget2.getScore(), DELTA); + assertEquals(0.33f, mShareTarget3.getScore(), DELTA); + assertEquals(0.4411f, mShareTarget4.getScore(), DELTA); + assertEquals(0f, mShareTarget5.getScore(), DELTA); + assertEquals(0f, mShareTarget6.getScore(), DELTA); + } + + @Test + public void testComputeScoreForAppShare_promoteFrequentlyUsedApps() { + when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1); + when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2); + when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3); + when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4); + when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5); + when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6); + when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7); + when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8); + when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9); + when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10); + when(mDataManager.queryAppLaunchCount(anyInt(), anyLong(), anyLong(), anySet())) + .thenReturn( + Map.of(PACKAGE_1, 1, + PACKAGE_2, 2, + PACKAGE_3, 3)); + + SharesheetModelScorer.computeScoreForAppShare( + List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5, + mShareTarget6), + Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID); + + verify(mDataManager, times(1)).queryAppLaunchCount(anyInt(), anyLong(), anyLong(), + anySet()); + assertEquals(0.9f, mShareTarget5.getScore(), DELTA); + assertEquals(0.81f, mShareTarget3.getScore(), DELTA); + assertEquals(0.729f, mShareTarget1.getScore(), DELTA); + assertEquals(0f, mShareTarget2.getScore(), DELTA); + assertEquals(0f, mShareTarget4.getScore(), DELTA); + assertEquals(0f, mShareTarget6.getScore(), DELTA); + } + + @Test + public void testComputeScoreForAppShare_skipPromoteFrequentlyUsedAppsWhenReachesLimit() { + when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1); + when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2); + when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3); + when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4); + when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5); + when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6); + when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7); + when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8); + when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9); + when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10); + when(mEventIndex1.getMostRecentActiveTimeSlot()).thenReturn(WITHIN_ONE_DAY); + when(mEventIndex2.getMostRecentActiveTimeSlot()).thenReturn(TWO_DAYS_AGO); + when(mEventIndex3.getMostRecentActiveTimeSlot()).thenReturn(FIVE_DAYS_AGO); + when(mEventIndex4.getMostRecentActiveTimeSlot()).thenReturn(EIGHT_DAYS_AGO); + when(mEventIndex5.getMostRecentActiveTimeSlot()).thenReturn(null); + when(mDataManager.queryAppLaunchCount(anyInt(), anyLong(), anyLong(), anySet())) + .thenReturn( + Map.of(PACKAGE_1, 1, + PACKAGE_2, 2, + PACKAGE_3, 3)); + + SharesheetModelScorer.computeScoreForAppShare( + List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5, + mShareTarget6), + Event.TYPE_SHARE_TEXT, 4, NOW, mDataManager, USER_ID); + + verify(mDataManager, never()).queryAppLaunchCount(anyInt(), anyLong(), anyLong(), anySet()); + assertEquals(0.4f, mShareTarget1.getScore(), DELTA); + assertEquals(0.35f, mShareTarget2.getScore(), DELTA); + assertEquals(0.33f, mShareTarget3.getScore(), DELTA); + assertEquals(0.31f, mShareTarget4.getScore(), DELTA); + assertEquals(0f, mShareTarget5.getScore(), DELTA); + assertEquals(0f, mShareTarget6.getScore(), DELTA); + } + + @Test + public void testComputeScoreForAppShare_promoteForegroundApp() { + when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1); + when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2); + when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3); + when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4); + when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5); + when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6); + when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7); + when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8); + when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9); + when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10); + when(mDataManager.queryAppMovingToForegroundEvents(anyInt(), anyLong(), + anyLong())).thenReturn( + List.of(createUsageEvent(PACKAGE_2), + createUsageEvent(PACKAGE_3), + createUsageEvent(SharesheetModelScorer.CHOOSER_ACTIVITY), + createUsageEvent(PACKAGE_3), + createUsageEvent(PACKAGE_3)) + ); + + SharesheetModelScorer.computeScoreForAppShare( + List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5, + mShareTarget6), + Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID); + + verify(mDataManager, times(1)).queryAppMovingToForegroundEvents(anyInt(), anyLong(), + anyLong()); + assertEquals(0f, mShareTarget1.getScore(), DELTA); + assertEquals(0f, mShareTarget2.getScore(), DELTA); + assertEquals(SharesheetModelScorer.FOREGROUND_APP_WEIGHT, mShareTarget3.getScore(), DELTA); + assertEquals(0f, mShareTarget4.getScore(), DELTA); + assertEquals(0f, mShareTarget5.getScore(), DELTA); + assertEquals(0f, mShareTarget6.getScore(), DELTA); + } + + @Test + public void testComputeScoreForAppShare_skipPromoteForegroundAppWhenNoValidForegroundApp() { + when(mEventHistory1.getEventIndex(anySet())).thenReturn(mEventIndex1); + when(mEventHistory2.getEventIndex(anySet())).thenReturn(mEventIndex2); + when(mEventHistory3.getEventIndex(anySet())).thenReturn(mEventIndex3); + when(mEventHistory4.getEventIndex(anySet())).thenReturn(mEventIndex4); + when(mEventHistory5.getEventIndex(anySet())).thenReturn(mEventIndex5); + when(mEventHistory1.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex6); + when(mEventHistory2.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex7); + when(mEventHistory3.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex8); + when(mEventHistory4.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex9); + when(mEventHistory5.getEventIndex(Event.TYPE_SHARE_TEXT)).thenReturn(mEventIndex10); + when(mDataManager.queryAppMovingToForegroundEvents(anyInt(), anyLong(), + anyLong())).thenReturn( + List.of(createUsageEvent(PACKAGE_3), + createUsageEvent(PACKAGE_3), + createUsageEvent(SharesheetModelScorer.CHOOSER_ACTIVITY), + createUsageEvent(PACKAGE_3), + createUsageEvent(PACKAGE_3)) + ); + + SharesheetModelScorer.computeScoreForAppShare( + List.of(mShareTarget1, mShareTarget2, mShareTarget3, mShareTarget4, mShareTarget5, + mShareTarget6), + Event.TYPE_SHARE_TEXT, 20, NOW, mDataManager, USER_ID); + + verify(mDataManager, times(1)).queryAppMovingToForegroundEvents(anyInt(), anyLong(), + anyLong()); + assertEquals(0f, mShareTarget1.getScore(), DELTA); + assertEquals(0f, mShareTarget2.getScore(), DELTA); + assertEquals(0f, mShareTarget3.getScore(), DELTA); + assertEquals(0f, mShareTarget4.getScore(), DELTA); + assertEquals(0f, mShareTarget5.getScore(), DELTA); + assertEquals(0f, mShareTarget6.getScore(), DELTA); + } + + private static UsageEvents.Event createUsageEvent(String packageName) { + UsageEvents.Event e = new UsageEvents.Event(); + e.mPackage = packageName; + return e; + } +} diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java index 40ada2aedd59..db1bbab7ed94 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java @@ -43,6 +43,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import com.android.frameworks.servicestests.R; +import com.android.server.pm.parsing.PackageParser2; import org.junit.Before; import org.junit.Test; @@ -63,6 +64,7 @@ public class ApexManagerTest { private static final int[] TEST_CHILD_SESSION_ID = {8888, 7777}; private ApexManager mApexManager; private Context mContext; + private PackageParser2 mPackageParser2; private IApexService mApexService = mock(IApexService.class); @@ -70,11 +72,14 @@ public class ApexManagerTest { public void setUp() throws RemoteException { mContext = InstrumentationRegistry.getInstrumentation().getContext(); mApexManager = new ApexManager.ApexManagerImpl(mApexService); + mPackageParser2 = new PackageParser2(null, false, null, null, null); } @Test public void testGetPackageInfo_setFlagsMatchActivePackage() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); final PackageInfo activePkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG, ApexManager.MATCH_ACTIVE_PACKAGE); @@ -90,6 +95,8 @@ public class ApexManagerTest { @Test public void testGetPackageInfo_setFlagsMatchFactoryPackage() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); PackageInfo factoryPkgPi = mApexManager.getPackageInfo(TEST_APEX_PKG, ApexManager.MATCH_FACTORY_PACKAGE); @@ -105,6 +112,8 @@ public class ApexManagerTest { @Test public void testGetPackageInfo_setFlagsNone() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); assertThat(mApexManager.getPackageInfo(TEST_APEX_PKG, 0)).isNull(); } @@ -112,6 +121,8 @@ public class ApexManagerTest { @Test public void testGetActivePackages() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, true)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); assertThat(mApexManager.getActivePackages()).isNotEmpty(); } @@ -119,6 +130,8 @@ public class ApexManagerTest { @Test public void testGetActivePackages_noneActivePackages() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); assertThat(mApexManager.getActivePackages()).isEmpty(); } @@ -126,6 +139,8 @@ public class ApexManagerTest { @Test public void testGetFactoryPackages() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); assertThat(mApexManager.getFactoryPackages()).isNotEmpty(); } @@ -133,6 +148,8 @@ public class ApexManagerTest { @Test public void testGetFactoryPackages_noneFactoryPackages() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); assertThat(mApexManager.getFactoryPackages()).isEmpty(); } @@ -140,6 +157,8 @@ public class ApexManagerTest { @Test public void testGetInactivePackages() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); assertThat(mApexManager.getInactivePackages()).isNotEmpty(); } @@ -147,6 +166,8 @@ public class ApexManagerTest { @Test public void testGetInactivePackages_noneInactivePackages() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(true, false)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); assertThat(mApexManager.getInactivePackages()).isEmpty(); } @@ -154,6 +175,8 @@ public class ApexManagerTest { @Test public void testIsApexPackage() throws RemoteException { when(mApexService.getAllPackages()).thenReturn(createApexInfo(false, true)); + mApexManager.scanApexPackagesTraced(mPackageParser2, + ParallelPackageParser.makeExecutorService()); assertThat(mApexManager.isApexPackage(TEST_APEX_PKG)).isTrue(); } diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/Android.bp b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/Android.bp deleted file mode 100644 index eb1a2921136d..000000000000 --- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/Android.bp +++ /dev/null @@ -1,37 +0,0 @@ -android_test { - name: "TunerResourceManagerTests", - - // Include all test java files. - srcs: [ - "*.java", - ], - - static_libs: [ - "frameworks-base-testutils", - "services.core", - "services.devicepolicy", - "guava", - "androidx.test.core", - "androidx.test.ext.truth", - "androidx.test.runner", - "androidx.test.rules", - "mockito-target-minus-junit4", - "platform-test-annotations", - "truth-prebuilt", - "testables", - "testng", - "servicestests-utils", - "service-permission", - - ], - - libs: [ - "android.test.mock", - "android.test.base", - "android.test.runner", - ], - - platform_apis: true, - test_suites: ["general-tests", "device-tests"], - compile_multilib: "both", -}
\ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidManifest.xml b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidManifest.xml deleted file mode 100644 index 9fa100d5a041..000000000000 --- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2020 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.server.tv.tunerresourcemanager"> - <application> - <uses-library android:name="android.test.runner" /> - </application> - <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.server.tv.tunerresourcemanager" - android:label="Tuner Resource Manager Test Cases"> - </instrumentation> -</manifest> - - - diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidTest.xml b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidTest.xml deleted file mode 100644 index e3ea6a06a115..000000000000 --- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/AndroidTest.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2020 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> -<configuration description="Runs Tests for Tuner Resource Manager"> - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> - <option name="test-file-name" value="TunerResourceManagerTests.apk" /> - </target_preparer> - - <option name="test-suite-tag" value="apct" /> - <option name="test-suite-tag" value="framework-base-presubmit" /> - <option name="test-tag" value="TunerResourceManagerTests" /> - <test class="com.android.tradefed.testtype.AndroidJUnitTest" > - <option name="package" value="com.android.server.tv.tunerresourcemanager" /> - <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" /> - <option name="hidden-api-checks" value="false"/> - </test> -</configuration>
\ No newline at end of file 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 c71d8194f889..08e492a7b0ff 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -28,7 +28,6 @@ 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.doReturn; @@ -38,7 +37,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; @@ -70,7 +68,7 @@ public class AppTransitionTests extends WindowTestsBase { @Before public void setUp() throws Exception { - doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean()); + doNothing().when(mWm.mRoot).performSurfacePlacement(); mDc = mWm.getDefaultDisplayContentLocked(); } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 6cc57f4dbf8c..cf3cfecbf65e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -174,7 +174,7 @@ public class AppWindowTokenTests extends WindowTestsBase { null /* freezeThisOneIfNeeded */, false /* forceUpdate */); // In this test, DC will not get config update. Set the waiting flag to false. mDisplayContent.mWaitingForConfig = false; - mWm.mRoot.performSurfacePlacement(false /* recoveringMemory */); + mWm.mRoot.performSurfacePlacement(); assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation()); assertTrue(appWindow.mResizeReported); appWindow.removeImmediately(); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 66566bc5dff5..da3ee3990137 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; @@ -28,6 +29,7 @@ import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.view.Display.DEFAULT_DISPLAY; +import static android.view.Display.TYPE_VIRTUAL; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -54,6 +56,7 @@ import static java.lang.Integer.MAX_VALUE; import android.app.ActivityManager.RecentTaskInfo; import android.app.ActivityManager.RunningTaskInfo; +import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.WindowConfiguration; import android.content.ComponentName; @@ -681,24 +684,19 @@ public class RecentTasksTest extends ActivityTestsBase { * Tests that tasks on singleTaskDisplay are not visible and not trimmed/removed. */ @Test - public void testVisibleTasks_singleTaskDisplay() { + public void testVisibleTasks_alwaysOnTop() { mRecentTasks.setOnlyTestVisibleRange(); mRecentTasks.setParameters(-1 /* min */, 3 /* max */, -1 /* ms */); - final DisplayContent singleTaskDisplay = - addNewDisplayContentAt(DisplayContent.POSITION_TOP); - singleTaskDisplay.setDisplayToSingleTaskInstance(); - ActivityStack singleTaskStack = singleTaskDisplay.createStack( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final DisplayContent display = mRootWindowContainer.getDefaultDisplay(); + final Task alwaysOnTopTask = display.createStack(WINDOWING_MODE_MULTI_WINDOW, + ACTIVITY_TYPE_STANDARD, true /* onTop */); + alwaysOnTopTask.setAlwaysOnTop(true); - Task excludedTask1 = createTaskBuilder(".ExcludedTask1") - .setStack(singleTaskStack) - .build(); + assertFalse("Always on top tasks should not be visible recents", + mRecentTasks.isVisibleRecentTask(alwaysOnTopTask)); - assertFalse("Tasks on singleTaskDisplay should not be visible recents", - mRecentTasks.isVisibleRecentTask(excludedTask1)); - - mRecentTasks.add(excludedTask1); + mRecentTasks.add(alwaysOnTopTask); // Add N+1 visible tasks. mRecentTasks.add(mTasks.get(0)); @@ -1366,12 +1364,12 @@ public class RecentTasksTest extends ActivityTestsBase { public boolean mLastAllowed; @Override - void getTasks(int maxNum, List<RunningTaskInfo> list, int ignoreActivityType, - int ignoreWindowingMode, RootWindowContainer root, - int callingUid, boolean allowed, boolean crossUser, ArraySet<Integer> profileIds) { + void getTasks(int maxNum, List<RunningTaskInfo> list, boolean filterOnlyVisibleRecents, + RootWindowContainer root, int callingUid, boolean allowed, boolean crossUser, + ArraySet<Integer> profileIds) { mLastAllowed = allowed; - super.getTasks(maxNum, list, ignoreActivityType, ignoreWindowingMode, root, - callingUid, allowed, crossUser, profileIds); + super.getTasks(maxNum, list, filterOnlyVisibleRecents, root, callingUid, allowed, + crossUser, profileIds); } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index f242989ab885..da07baca3ce1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -100,7 +100,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean()); + doNothing().when(mWm.mRoot).performSurfacePlacement(); when(mMockRunner.asBinder()).thenReturn(new Binder()); mDefaultDisplay = mWm.mRoot.getDefaultDisplay(); mController = spy(new RecentsAnimationController(mWm, mMockRunner, mAnimationCallbacks, diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index 0d5565428bf2..d6a67abc9e76 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -16,9 +16,6 @@ package com.android.server.wm; -import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; -import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; - import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; @@ -82,9 +79,8 @@ public class RunningTasksTest extends ActivityTestsBase { // collected from all tasks across all the stacks final int numFetchTasks = 5; ArrayList<RunningTaskInfo> tasks = new ArrayList<>(); - mRunningTasks.getTasks(5, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, - mRootWindowContainer, -1 /* callingUid */, true /* allowed */, - true /*crossUser */, PROFILE_IDS); + mRunningTasks.getTasks(5, tasks, false /* filterOnlyVisibleRecents */, mRootWindowContainer, + -1 /* callingUid */, true /* allowed */, true /*crossUser */, PROFILE_IDS); assertThat(tasks).hasSize(numFetchTasks); for (int i = 0; i < numFetchTasks; i++) { assertEquals(numTasks - i - 1, tasks.get(i).id); @@ -93,9 +89,9 @@ public class RunningTasksTest extends ActivityTestsBase { // Ensure that requesting more than the total number of tasks only returns the subset // and does not crash tasks.clear(); - mRunningTasks.getTasks(100, tasks, ACTIVITY_TYPE_UNDEFINED, WINDOWING_MODE_UNDEFINED, - mRootWindowContainer, -1 /* callingUid */, true /* allowed */, - true /* crossUser */, PROFILE_IDS); + mRunningTasks.getTasks(100, tasks, false /* filterOnlyVisibleRecents */, + mRootWindowContainer, -1 /* callingUid */, true /* allowed */, true /* crossUser */, + PROFILE_IDS); assertThat(tasks).hasSize(numTasks); for (int i = 0; i < numTasks; i++) { assertEquals(numTasks - i - 1, tasks.get(i).id); @@ -119,9 +115,9 @@ public class RunningTasksTest extends ActivityTestsBase { final int numFetchTasks = 5; final ArrayList<RunningTaskInfo> tasks = new ArrayList<>(); - mRunningTasks.getTasks(numFetchTasks, tasks, ACTIVITY_TYPE_UNDEFINED, - WINDOWING_MODE_UNDEFINED, mRootWindowContainer, -1 /* callingUid */, - true /* allowed */, true /*crossUser */, PROFILE_IDS); + mRunningTasks.getTasks(numFetchTasks, tasks, false /* filterOnlyVisibleRecents */, + mRootWindowContainer, -1 /* callingUid */, true /* allowed */, true /*crossUser */, + PROFILE_IDS); assertThat(tasks).hasSize(numFetchTasks); for (int i = 0; i < tasks.size(); i++) { final Bundle extras = tasks.get(i).baseIntent.getExtras(); diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java index edf81ea32ad3..893a14541c48 100644 --- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java @@ -481,7 +481,7 @@ public class SizeCompatTests extends ActivityTestsBase { // The letterbox needs a main window to layout. addWindowToActivity(mActivity); // Compute the frames of the window and invoke {@link ActivityRecord#layoutLetterbox}. - mActivity.mRootWindowContainer.performSurfacePlacement(false /* recoveringMemory */); + mActivity.mRootWindowContainer.performSurfacePlacement(); // The letterbox insets should be [350, 0 - 350, 0]. assertEquals(new Rect(mActivity.getBounds().left, 0, dh - mActivity.getBounds().right, 0), mActivity.getLetterboxInsets()); diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java index 558f4cd24471..39a754389254 100644 --- a/telephony/java/android/telephony/AccessNetworkConstants.java +++ b/telephony/java/android/telephony/AccessNetworkConstants.java @@ -19,9 +19,9 @@ package android.telephony; import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.hardware.radio.V1_1.EutranBands; import android.hardware.radio.V1_1.GeranBands; import android.hardware.radio.V1_5.AccessNetwork; +import android.hardware.radio.V1_5.EutranBands; import android.hardware.radio.V1_5.UtranBands; import java.lang.annotation.Retention; @@ -212,7 +212,8 @@ public final class AccessNetworkConstants { /** * Frequency bands for EUTRAN. - * http://www.etsi.org/deliver/etsi_ts/136100_136199/136101/14.03.00_60/ts_136101v140p.pdf + * 3GPP TS 36.101, Version 16.4.0, Table 5.5: Operating bands + * https://www.etsi.org/deliver/etsi_ts/136100_136199/136101/15.09.00_60/ts_136101v150900p.pdf */ public static final class EutranBand { public static final int BAND_1 = EutranBands.BAND_1; @@ -259,10 +260,22 @@ public final class AccessNetworkConstants { public static final int BAND_46 = EutranBands.BAND_46; public static final int BAND_47 = EutranBands.BAND_47; public static final int BAND_48 = EutranBands.BAND_48; + public static final int BAND_49 = EutranBands.BAND_49; + public static final int BAND_50 = EutranBands.BAND_50; + public static final int BAND_51 = EutranBands.BAND_51; + public static final int BAND_52 = EutranBands.BAND_52; + public static final int BAND_53 = EutranBands.BAND_53; public static final int BAND_65 = EutranBands.BAND_65; public static final int BAND_66 = EutranBands.BAND_66; public static final int BAND_68 = EutranBands.BAND_68; public static final int BAND_70 = EutranBands.BAND_70; + public static final int BAND_71 = EutranBands.BAND_71; + public static final int BAND_72 = EutranBands.BAND_72; + public static final int BAND_73 = EutranBands.BAND_73; + public static final int BAND_74 = EutranBands.BAND_74; + public static final int BAND_85 = EutranBands.BAND_85; + public static final int BAND_87 = EutranBands.BAND_87; + public static final int BAND_88 = EutranBands.BAND_88; /** @hide */ private EutranBand() {}; @@ -305,9 +318,11 @@ public final class AccessNetworkConstants { /** * Frequency bands for NGRAN + * https://www.etsi.org/deliver/etsi_ts/138100_138199/13810101/15.08.02_60/ts_13810101v150802p.pdf + * https://www.etsi.org/deliver/etsi_ts/138100_138199/13810102/15.08.00_60/ts_13810102v150800p.pdf */ public static final class NgranBands { - /** FR1 bands */ + /** 3GPP TS 38.101-1, Version 16.2.0, Table 5.2-1: FR1 bands */ public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1; public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2; public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3; @@ -346,9 +361,15 @@ public final class AccessNetworkConstants { public static final int BAND_83 = android.hardware.radio.V1_5.NgranBands.BAND_83; public static final int BAND_84 = android.hardware.radio.V1_5.NgranBands.BAND_84; public static final int BAND_86 = android.hardware.radio.V1_5.NgranBands.BAND_86; + public static final int BAND_89 = android.hardware.radio.V1_5.NgranBands.BAND_89; public static final int BAND_90 = android.hardware.radio.V1_5.NgranBands.BAND_90; + public static final int BAND_91 = android.hardware.radio.V1_5.NgranBands.BAND_91; + public static final int BAND_92 = android.hardware.radio.V1_5.NgranBands.BAND_92; + public static final int BAND_93 = android.hardware.radio.V1_5.NgranBands.BAND_93; + public static final int BAND_94 = android.hardware.radio.V1_5.NgranBands.BAND_94; + public static final int BAND_95 = android.hardware.radio.V1_5.NgranBands.BAND_95; - /** FR2 bands */ + /** 3GPP TS 38.101-2, Version 16.2.0, Table 5.2-1: FR2 bands */ public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257; public static final int BAND_258 = android.hardware.radio.V1_5.NgranBands.BAND_258; public static final int BAND_260 = android.hardware.radio.V1_5.NgranBands.BAND_260; @@ -398,7 +419,13 @@ public final class AccessNetworkConstants { BAND_83, BAND_84, BAND_86, + BAND_89, BAND_90, + BAND_91, + BAND_92, + BAND_93, + BAND_94, + BAND_95, BAND_257, BAND_258, BAND_260, @@ -495,7 +522,13 @@ public final class AccessNetworkConstants { case BAND_83: case BAND_84: case BAND_86: + case BAND_89: case BAND_90: + case BAND_91: + case BAND_92: + case BAND_93: + case BAND_94: + case BAND_95: return FREQUENCY_RANGE_GROUP_1; case BAND_257: case BAND_258: diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java index 5d2c225f28ec..981ed450004a 100644 --- a/telephony/java/android/telephony/AccessNetworkUtils.java +++ b/telephony/java/android/telephony/AccessNetworkUtils.java @@ -34,12 +34,10 @@ public class AccessNetworkUtils { return DUPLEX_MODE_UNKNOWN; } - if (band >= EutranBand.BAND_68) { + if (band > EutranBand.BAND_88) { return DUPLEX_MODE_UNKNOWN; } else if (band >= EutranBand.BAND_65) { return DUPLEX_MODE_FDD; - } else if (band >= EutranBand.BAND_47) { - return DUPLEX_MODE_UNKNOWN; } else if (band >= EutranBand.BAND_33) { return DUPLEX_MODE_TDD; } else if (band >= EutranBand.BAND_1) { @@ -58,17 +56,53 @@ public class AccessNetworkUtils { * @return Operating band number, or {@link #INVALID_BAND} if no corresponding band exists */ public static int getOperatingBandForEarfcn(int earfcn) { - if (earfcn > 67535) { + if (earfcn > 70645) { + return INVALID_BAND; + } else if (earfcn >= 70596) { + return EutranBand.BAND_88; + } else if (earfcn >= 70546) { + return EutranBand.BAND_87; + } else if (earfcn >= 70366) { + return EutranBand.BAND_85; + } else if (earfcn > 69465) { + return INVALID_BAND; + } else if (earfcn >= 69036) { + return EutranBand.BAND_74; + } else if (earfcn >= 68986) { + return EutranBand.BAND_73; + } else if (earfcn >= 68936) { + return EutranBand.BAND_72; + } else if (earfcn >= 68586) { + return EutranBand.BAND_71; + } else if (earfcn >= 68336) { + return EutranBand.BAND_70; + } else if (earfcn > 67835) { return INVALID_BAND; + } else if (earfcn >= 67536) { + return EutranBand.BAND_68; } else if (earfcn >= 67366) { return INVALID_BAND; // band 67 only for CarrierAgg } else if (earfcn >= 66436) { return EutranBand.BAND_66; } else if (earfcn >= 65536) { return EutranBand.BAND_65; - } else if (earfcn > 54339) { + } else if (earfcn > 60254) { return INVALID_BAND; - } else if (earfcn >= 46790 /* inferred from the end range of BAND_45 */) { + } else if (earfcn >= 60140) { + return EutranBand.BAND_53; + } else if (earfcn >= 59140) { + return EutranBand.BAND_52; + } else if (earfcn >= 59090) { + return EutranBand.BAND_51; + } else if (earfcn >= 58240) { + return EutranBand.BAND_50; + } else if (earfcn >= 56740) { + return EutranBand.BAND_49; + } else if (earfcn >= 55240) { + return EutranBand.BAND_48; + } else if (earfcn >= 54540) { + return EutranBand.BAND_47; + } else if (earfcn >= 46790) { return EutranBand.BAND_46; } else if (earfcn >= 46590) { return EutranBand.BAND_45; diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index c1447465f53f..991375c5bc73 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -2520,7 +2520,6 @@ public final class SmsManager { * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully sent, or failed * @throws IllegalArgumentException if contentUri is empty - * @deprecated use {@link MmsManager#sendMultimediaMessage} instead. */ public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl, Bundle configOverrides, PendingIntent sentIntent) { @@ -2555,7 +2554,6 @@ public final class SmsManager { * @param downloadedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is downloaded, or the download is failed * @throws IllegalArgumentException if locationUrl or contentUri is empty - * @deprecated use {@link MmsManager#downloadMultimediaMessage} instead. */ public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent) { diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java index bb4e00ba1ef9..f2f0be73c010 100644 --- a/test-runner/src/android/test/TouchUtils.java +++ b/test-runner/src/android/test/TouchUtils.java @@ -223,7 +223,7 @@ public class TouchUtils { public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v, int stepCount) { int screenHeight = - activity.getWindowManager().getCurrentWindowMetrics().getSize().getHeight(); + activity.getWindowManager().getCurrentWindowMetrics().getBounds().height(); int[] xy = new int[2]; v.getLocationOnScreen(xy); diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index f444b77b738e..0ad30391d1a8 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -46,6 +46,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; @@ -72,6 +73,7 @@ public class AppLaunch extends InstrumentationTestCase { private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts"; private static final String KEY_APPS = "apps"; private static final String KEY_IORAP_TRIAL_LAUNCH = "iorap_trial_launch"; + private static final String KEY_IORAP_COMPILER_FILTERS = "iorap_compiler_filters"; private static final String KEY_TRIAL_LAUNCH = "trial_launch"; private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations"; private static final String KEY_LAUNCH_ORDER = "launch_order"; @@ -153,6 +155,7 @@ public class AppLaunch extends InstrumentationTestCase { private BufferedWriter mBufferedWriter = null; private boolean mSimplePerfAppOnly = false; private String[] mCompilerFilters = null; + private List<String> mIorapCompilerFilters = null; private String mLastAppName = ""; private boolean mCycleCleanUp = false; private boolean mTraceAll = false; @@ -618,6 +621,24 @@ public class AppLaunch extends InstrumentationTestCase { return reason; } + private boolean shouldIncludeIorap(String compilerFilter) { + if (!mIorapTrialLaunch) { + return false; + } + + // No iorap compiler filters specified: treat all compiler filters as ok. + if (mIorapCompilerFilters == null) { + return true; + } + + // iorap compiler filters specified: the compilerFilter must be in the whitelist. + if (mIorapCompilerFilters.indexOf(compilerFilter) != -1) { + return true; + } + + return false; + } + /** * If launch order is "cyclic" then apps will be launched one after the * other for each iteration count. @@ -632,7 +653,7 @@ public class AppLaunch extends InstrumentationTestCase { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false)); } } - if (mIorapTrialLaunch) { + if (shouldIncludeIorap(compilerFilter)) { for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) { for (String app : mNameToResultKey.keySet()) { String reason = makeReasonForIorapTrialLaunch(launchCount); @@ -646,14 +667,16 @@ public class AppLaunch extends InstrumentationTestCase { for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) { for (String app : mNameToResultKey.keySet()) { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, - String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch)); + String.format(LAUNCH_ITERATION, launchCount), + shouldIncludeIorap(compilerFilter))); } } if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) { for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) { for (String app : mNameToResultKey.keySet()) { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, - String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch)); + String.format(TRACE_ITERATION, traceCount), + shouldIncludeIorap(compilerFilter))); } } } @@ -664,7 +687,7 @@ public class AppLaunch extends InstrumentationTestCase { if (mTrialLaunch) { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false)); } - if (mIorapTrialLaunch) { + if (shouldIncludeIorap(compilerFilter)) { for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) { String reason = makeReasonForIorapTrialLaunch(launchCount); mLaunchOrderList.add( @@ -675,12 +698,14 @@ public class AppLaunch extends InstrumentationTestCase { } for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, - String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch)); + String.format(LAUNCH_ITERATION, launchCount), + shouldIncludeIorap(compilerFilter))); } if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) { for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, - String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch)); + String.format(TRACE_ITERATION, traceCount), + shouldIncludeIorap(compilerFilter))); } } } @@ -822,6 +847,13 @@ public class AppLaunch extends InstrumentationTestCase { mCompilerFilters = new String[1]; } + String iorapCompilerFilterList = args.getString(KEY_IORAP_COMPILER_FILTERS); + if (iorapCompilerFilterList != null) { + // Passing in iorap compiler filters implies an iorap trial launch. + mIorapTrialLaunch = true; + mIorapCompilerFilters = Arrays.asList(iorapCompilerFilterList.split("\\|")); + } + // Pre-populate the results map to avoid null checks. for (String app : mNameToLaunchTime.keySet()) { HashMap<String, List<AppLaunchResult>> map = new HashMap<>(); diff --git a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java index e255ce234c65..31532a226800 100644 --- a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java +++ b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java @@ -27,7 +27,6 @@ import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.RemoteException; -import android.util.Size; import android.view.Gravity; import android.view.IWindowManager; import android.view.MotionEvent; @@ -90,8 +89,8 @@ public class MirrorSurfaceActivity extends Activity implements View.OnClickListe .getSystemService(WindowManager.class); mIWm = WindowManagerGlobal.getWindowManagerService(); - Size windowSize = mWm.getCurrentWindowMetrics().getSize(); - mWindowBounds.set(0, 0, windowSize.getWidth(), windowSize.getHeight()); + Rect windowBounds = mWm.getCurrentWindowMetrics().getBounds(); + mWindowBounds.set(0, 0, windowBounds.width(), windowBounds.height()); mScaleText = findViewById(R.id.scale); mDisplayFrameText = findViewById(R.id.displayFrame); diff --git a/wifi/Android.bp b/wifi/Android.bp index d0f1a26f7dbf..614786193a18 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -81,7 +81,6 @@ java_library { libs: [ "framework-annotations-lib", "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage - "unsupportedappusage-annotation", // for dalvik.annotation.compat.UnsupportedAppUsage "framework-telephony-stubs", ], srcs: [ |