Merge "WindowContainerTransaction: Support PIP Transition" into rvc-dev
diff --git a/Android.bp b/Android.bp
index 78d38c5..9c1a085 100644
--- a/Android.bp
+++ b/Android.bp
@@ -281,17 +281,33 @@
filegroup {
name: "framework-updatable-sources",
srcs: [
- ":framework-sdkextensions-sources",
- ":framework-statsd-sources",
- ":framework-tethering-srcs",
- ":updatable-media-srcs",
":framework-mediaprovider-sources",
":framework-permission-sources",
- ":framework-wifi-updatable-sources",
+ ":framework-sdkextensions-sources",
+ ":framework-statsd-sources",
":framework-telephony-sources",
+ ":framework-tethering-srcs",
+ ":framework-wifi-updatable-sources",
+ ":updatable-media-srcs",
]
}
+java_library {
+ name: "framework-updatable-stubs-module_libs_api",
+ static_libs: [
+ "framework-media-stubs-module_libs_api",
+ "framework-mediaprovider-stubs-module_libs_api",
+ "framework-permission-stubs-module_libs_api",
+ "framework-sdkextensions-stubs-module_libs_api",
+ "framework-statsd-stubs-module_libs_api",
+ "framework-telephony-stubs", // TODO: Update to module_libs_api when there is one.
+ "framework-tethering-stubs-module_libs_api",
+ "framework-wifi-stubs-module_libs_api",
+ ],
+ sdk_version: "module_current",
+ visibility: [":__pkg__"],
+}
+
filegroup {
name: "framework-all-sources",
srcs: [
@@ -307,7 +323,6 @@
name: "framework-aidl-export-defaults",
aidl: {
export_include_dirs: [
- "apex/media/framework/java",
"core/java",
"drm/java",
"graphics/java",
@@ -324,6 +339,12 @@
"rs/java",
"sax/java",
"telecomm/java",
+
+ // TODO(b/148660295): remove this
+ "apex/media/framework/java",
+
+ // TODO(b/147699819): remove this
+ "telephony/java",
],
},
}
@@ -397,9 +418,7 @@
"app-compat-annotations",
"ext",
"unsupportedappusage",
- "framework-media-stubs-systemapi",
- "framework-mediaprovider-stubs-systemapi",
- "framework-telephony-stubs",
+ "framework-updatable-stubs-module_libs_api",
],
jarjar_rules: ":framework-jarjar-rules",
@@ -465,13 +484,6 @@
name: "framework-minus-apex",
defaults: ["framework-defaults"],
srcs: [":framework-non-updatable-sources"],
- libs: [
- "framework-sdkextensions-stubs-systemapi",
- "framework-statsd-stubs-module_libs_api",
- "framework-permission-stubs-systemapi",
- "framework-wifi-stubs-systemapi",
- "framework-tethering-stubs",
- ],
installable: true,
javac_shard_size: 150,
required: [
@@ -512,16 +524,9 @@
installable: false, // this lib is a build-only library
static_libs: [
"framework-minus-apex",
- "framework-media-stubs-systemapi",
- "framework-mediaprovider-stubs-systemapi",
- "framework-permission-stubs-systemapi",
- "framework-sdkextensions-stubs-systemapi",
- "framework-statsd-stubs-module_libs_api",
- "framework-wifi-stubs-systemapi",
- "framework-tethering-stubs",
- // TODO (b/147688669) should be framework-telephony-stubs
+ // TODO (b/147688669) should be removed
"framework-telephony",
- // TODO(jiyong): add stubs for APEXes here
+ "framework-updatable-stubs-module_libs_api",
],
sdk_version: "core_platform",
apex_available: ["//apex_available:platform"],
@@ -540,7 +545,6 @@
visibility: [
// DO NOT ADD ANY MORE ENTRIES TO THIS LIST
"//external/robolectric-shadows:__subpackages__",
- "//frameworks/base/packages/Tethering/common/TetheringLib:__subpackages__",
"//frameworks/layoutlib:__subpackages__",
"//frameworks/opt/net/ike:__subpackages__",
],
diff --git a/apex/Android.bp b/apex/Android.bp
index 051986e..1510911 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -43,6 +43,7 @@
name: "framework-module-stubs-defaults-publicapi",
args: mainline_stubs_args,
installable: false,
+ sdk_version: "current",
}
stubs_defaults {
@@ -50,6 +51,7 @@
args: mainline_stubs_args + priv_apps,
srcs: [":framework-annotations"],
installable: false,
+ sdk_version: "system_current",
}
// The defaults for module_libs comes in two parts - defaults for API checks
@@ -62,6 +64,7 @@
args: mainline_stubs_args + module_libs,
srcs: [":framework-annotations"],
installable: false,
+ sdk_version: "module_current",
}
stubs_defaults {
@@ -69,4 +72,5 @@
args: mainline_stubs_args + module_libs + priv_apps,
srcs: [":framework-annotations"],
installable: false,
+ sdk_version: "module_current",
}
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index b219fd41..29c48ad 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -139,7 +139,7 @@
* @Override
* public void onSampleCompleted(
* int trackIndex,
- * long timeUs,
+ * long timeMicros,
* int flags,
* int size,
* int offset,
@@ -163,7 +163,7 @@
* /* destPos= */ 0,
* /* size= */ offset);
* bytesWrittenCount = bytesWrittenCount - offset;
- * publishSample(sampleData, timeUs, flags);
+ * publishSample(sampleData, timeMicros, flags);
* }
*
* private void ensureSpaceInBuffer(int numberOfBytesToRead) {
@@ -187,7 +187,7 @@
*/
public static final class SeekMap {
- /** Returned by {@link #getDurationUs()} when the duration is unknown. */
+ /** Returned by {@link #getDurationMicros()} when the duration is unknown. */
public static final int UNKNOWN_DURATION = Integer.MIN_VALUE;
private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap;
@@ -205,26 +205,26 @@
* Returns the duration of the stream in microseconds or {@link #UNKNOWN_DURATION} if the
* duration is unknown.
*/
- public long getDurationUs() {
+ public long getDurationMicros() {
return mExoPlayerSeekMap.getDurationUs();
}
/**
* Obtains {@link SeekPoint SeekPoints} for the specified seek time in microseconds.
*
- * <p>{@code getSeekPoints(timeUs).first} contains the latest seek point for samples with
- * timestamp equal to or smaller than {@code timeUs}.
+ * <p>{@code getSeekPoints(timeMicros).first} contains the latest seek point for samples
+ * with timestamp equal to or smaller than {@code timeMicros}.
*
- * <p>{@code getSeekPoints(timeUs).second} contains the earliest seek point for samples with
- * timestamp equal to or greater than {@code timeUs}. If a seek point exists for {@code
- * timeUs}, the returned pair will contain the same {@link SeekPoint} twice.
+ * <p>{@code getSeekPoints(timeMicros).second} contains the earliest seek point for samples
+ * with timestamp equal to or greater than {@code timeMicros}. If a seek point exists for
+ * {@code timeMicros}, the returned pair will contain the same {@link SeekPoint} twice.
*
- * @param timeUs A seek time in microseconds.
+ * @param timeMicros A seek time in microseconds.
* @return The corresponding {@link SeekPoint SeekPoints}.
*/
@NonNull
- public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs) {
- SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeUs);
+ public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeMicros) {
+ SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeMicros);
return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second));
}
}
@@ -254,24 +254,24 @@
@NonNull public static final SeekPoint START = new SeekPoint(0, 0);
/** The time of the seek point, in microseconds. */
- public final long timeUs;
+ public final long timeMicros;
/** The byte offset of the seek point. */
public final long position;
/**
- * @param timeUs The time of the seek point, in microseconds.
+ * @param timeMicros The time of the seek point, in microseconds.
* @param position The byte offset of the seek point.
*/
- private SeekPoint(long timeUs, long position) {
- this.timeUs = timeUs;
+ private SeekPoint(long timeMicros, long position) {
+ this.timeMicros = timeMicros;
this.position = position;
}
@Override
@NonNull
public String toString() {
- return "[timeUs=" + timeUs + ", position=" + position + "]";
+ return "[timeMicros=" + timeMicros + ", position=" + position + "]";
}
@Override
@@ -283,12 +283,12 @@
return false;
}
SeekPoint other = (SeekPoint) obj;
- return timeUs == other.timeUs && position == other.position;
+ return timeMicros == other.timeMicros && position == other.position;
}
@Override
public int hashCode() {
- int result = (int) timeUs;
+ int result = (int) timeMicros;
result = 31 * result + (int) position;
return result;
}
@@ -345,25 +345,25 @@
*
* @param seekMap The extracted {@link SeekMap}.
*/
- void onSeekMap(@NonNull SeekMap seekMap);
+ void onSeekMapFound(@NonNull SeekMap seekMap);
/**
* Called when the number of tracks is found.
*
* @param numberOfTracks The number of tracks in the stream.
*/
- void onTracksFound(int numberOfTracks);
+ void onTrackCountFound(int numberOfTracks);
/**
- * Called when new {@link TrackData} is extracted from the stream.
+ * Called when new {@link TrackData} is found in the stream.
*
* @param trackIndex The index of the track for which the {@link TrackData} was extracted.
* @param trackData The extracted {@link TrackData}.
*/
- void onTrackData(int trackIndex, @NonNull TrackData trackData);
+ void onTrackDataFound(int trackIndex, @NonNull TrackData trackData);
/**
- * Called to write sample data to the output.
+ * Called when sample data is found in the stream.
*
* <p>If the invocation of this method returns before the entire {@code inputReader} {@link
* InputReader#getLength() length} is consumed, the method will be called again for the
@@ -374,15 +374,15 @@
* @param inputReader The {@link InputReader} from which to read the data.
* @throws IOException If an exception occurs while reading from {@code inputReader}.
*/
- void onSampleData(int trackIndex, @NonNull InputReader inputReader) throws IOException;
+ void onSampleDataFound(int trackIndex, @NonNull InputReader inputReader) throws IOException;
/**
- * Called once all the data of a sample has been passed to {@link #onSampleData}.
+ * Called once all the data of a sample has been passed to {@link #onSampleDataFound}.
*
* <p>Also includes sample metadata, like presentation timestamp and flags.
*
* @param trackIndex The index of the track to which the sample corresponds.
- * @param timeUs The media timestamp associated with the sample, in microseconds.
+ * @param timeMicros The media timestamp associated with the sample, in microseconds.
* @param flags Flags associated with the sample. See {@link MediaCodec
* MediaCodec.BUFFER_FLAG_*}.
* @param size The size of the sample data, in bytes.
@@ -394,7 +394,7 @@
*/
void onSampleCompleted(
int trackIndex,
- long timeUs,
+ long timeMicros,
int flags,
int size,
int offset,
@@ -632,7 +632,7 @@
private Extractor mExtractor;
private ExtractorInput mExtractorInput;
private long mPendingSeekPosition;
- private long mPendingSeekTimeUs;
+ private long mPendingSeekTimeMicros;
// Public methods.
@@ -760,7 +760,7 @@
}
if (isPendingSeek()) {
- mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeUs);
+ mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeMicros);
removePendingSeek();
}
@@ -786,7 +786,7 @@
* Seeks within the media container being extracted.
*
* <p>{@link SeekPoint SeekPoints} can be obtained from the {@link SeekMap} passed to {@link
- * OutputConsumer#onSeekMap(SeekMap)}.
+ * OutputConsumer#onSeekMapFound(SeekMap)}.
*
* <p>Following a call to this method, the {@link InputReader} passed to the next invocation of
* {@link #advance} must provide data starting from {@link SeekPoint#position} in the stream.
@@ -796,9 +796,9 @@
public void seek(@NonNull SeekPoint seekPoint) {
if (mExtractor == null) {
mPendingSeekPosition = seekPoint.position;
- mPendingSeekTimeUs = seekPoint.timeUs;
+ mPendingSeekTimeMicros = seekPoint.timeMicros;
} else {
- mExtractor.seek(seekPoint.position, seekPoint.timeUs);
+ mExtractor.seek(seekPoint.position, seekPoint.timeMicros);
}
}
@@ -836,7 +836,7 @@
private void removePendingSeek() {
mPendingSeekPosition = -1;
- mPendingSeekTimeUs = -1;
+ mPendingSeekTimeMicros = -1;
}
// Private classes.
@@ -897,12 +897,12 @@
@Override
public void endTracks() {
- mOutputConsumer.onTracksFound(mTrackOutputAdapters.size());
+ mOutputConsumer.onTrackCountFound(mTrackOutputAdapters.size());
}
@Override
public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
- mOutputConsumer.onSeekMap(new SeekMap(exoplayerSeekMap));
+ mOutputConsumer.onSeekMapFound(new SeekMap(exoplayerSeekMap));
}
}
@@ -916,7 +916,7 @@
@Override
public void format(Format format) {
- mOutputConsumer.onTrackData(
+ mOutputConsumer.onTrackDataFound(
mTrackIndex,
new TrackData(
toMediaFormat(format), toFrameworkDrmInitData(format.drmInitData)));
@@ -927,7 +927,7 @@
throws IOException {
mScratchExtractorInputAdapter.setExtractorInput(input, length);
long positionBeforeReading = mScratchExtractorInputAdapter.getPosition();
- mOutputConsumer.onSampleData(mTrackIndex, mScratchExtractorInputAdapter);
+ mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchExtractorInputAdapter);
return (int) (mScratchExtractorInputAdapter.getPosition() - positionBeforeReading);
}
@@ -935,7 +935,7 @@
public void sampleData(ParsableByteArray data, int length) {
mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
try {
- mOutputConsumer.onSampleData(mTrackIndex, mScratchParsableByteArrayAdapter);
+ mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchParsableByteArrayAdapter);
} catch (IOException e) {
// Unexpected.
throw new RuntimeException(e);
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
index 0d163cf..aedba29 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
@@ -40,7 +40,7 @@
* @return the runtime permissions read
*/
@Nullable
- RuntimePermissionsState readAsUser(@NonNull UserHandle user);
+ RuntimePermissionsState readForUser(@NonNull UserHandle user);
/**
* Write the runtime permissions to persistence.
@@ -50,7 +50,8 @@
* @param runtimePermissions the runtime permissions to write
* @param user the user to write for
*/
- void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user);
+ void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
+ @NonNull UserHandle user);
/**
* Delete the runtime permissions from persistence.
@@ -59,7 +60,7 @@
*
* @param user the user to delete for
*/
- void deleteAsUser(@NonNull UserHandle user);
+ void deleteForUser(@NonNull UserHandle user);
/**
* Create a new instance of {@link RuntimePermissionsPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
index 0ac0c73..e43f59a 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
@@ -67,7 +67,7 @@
@Nullable
@Override
- public RuntimePermissionsState readAsUser(@NonNull UserHandle user) {
+ public RuntimePermissionsState readForUser(@NonNull UserHandle user) {
File file = getFile(user);
try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
XmlPullParser parser = Xml.newPullParser();
@@ -172,7 +172,7 @@
}
@Override
- public void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions,
+ public void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
@NonNull UserHandle user) {
File file = getFile(user);
AtomicFile atomicFile = new AtomicFile(file);
@@ -252,7 +252,7 @@
}
@Override
- public void deleteAsUser(@NonNull UserHandle user) {
+ public void deleteForUser(@NonNull UserHandle user) {
getFile(user).delete();
}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
index cd2750a..c6bfc6d 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* State of all runtime permissions.
@@ -61,6 +62,14 @@
@NonNull
private final Map<String, List<PermissionState>> mSharedUserPermissions;
+ /**
+ * Create a new instance of this class.
+ *
+ * @param version the version of the runtime permissions
+ * @param fingerprint the fingerprint of the runtime permissions
+ * @param packagePermissions the runtime permissions by packages
+ * @param sharedUserPermissions the runtime permissions by shared users
+ */
public RuntimePermissionsState(int version, @Nullable String fingerprint,
@NonNull Map<String, List<PermissionState>> packagePermissions,
@NonNull Map<String, List<PermissionState>> sharedUserPermissions) {
@@ -70,32 +79,72 @@
mSharedUserPermissions = sharedUserPermissions;
}
+ /**
+ * Get the version of the runtime permissions.
+ *
+ * @return the version of the runtime permissions
+ */
public int getVersion() {
return mVersion;
}
+ /**
+ * Get the fingerprint of the runtime permissions.
+ *
+ * @return the fingerprint of the runtime permissions
+ */
@Nullable
public String getFingerprint() {
return mFingerprint;
}
+ /**
+ * Get the runtime permissions by packages.
+ *
+ * @return the runtime permissions by packages
+ */
@NonNull
public Map<String, List<PermissionState>> getPackagePermissions() {
return mPackagePermissions;
}
+ /**
+ * Get the runtime permissions by shared users.
+ *
+ * @return the runtime permissions by shared users
+ */
@NonNull
public Map<String, List<PermissionState>> getSharedUserPermissions() {
return mSharedUserPermissions;
}
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+ RuntimePermissionsState that = (RuntimePermissionsState) object;
+ return mVersion == that.mVersion
+ && Objects.equals(mFingerprint, that.mFingerprint)
+ && Objects.equals(mPackagePermissions, that.mPackagePermissions)
+ && Objects.equals(mSharedUserPermissions, that.mSharedUserPermissions);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mVersion, mFingerprint, mPackagePermissions, mSharedUserPermissions);
+ }
+
/**
* State of a single permission.
*/
- public static class PermissionState {
+ public static final class PermissionState {
/**
- * Name of the permission.
+ * The name of the permission.
*/
@NonNull
private final String mName;
@@ -106,27 +155,68 @@
private final boolean mGranted;
/**
- * Flags of the permission.
+ * The flags of the permission.
*/
private final int mFlags;
+ /**
+ * Create a new instance of this class.
+ *
+ * @param name the name of the permission
+ * @param granted whether the permission is granted
+ * @param flags the flags of the permission
+ */
public PermissionState(@NonNull String name, boolean granted, int flags) {
mName = name;
mGranted = granted;
mFlags = flags;
}
+ /**
+ * Get the name of the permission.
+ *
+ * @return the name of the permission
+ */
@NonNull
public String getName() {
return mName;
}
+ /**
+ * Get whether the permission is granted.
+ *
+ * @return whether the permission is granted
+ */
public boolean isGranted() {
return mGranted;
}
+ /**
+ * Get the flags of the permission.
+ *
+ * @return the flags of the permission
+ */
public int getFlags() {
return mFlags;
}
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+ PermissionState that = (PermissionState) object;
+ return mGranted == that.mGranted
+ && mFlags == that.mFlags
+ && Objects.equals(mName, that.mName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mGranted, mFlags);
+ }
}
}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
index 64d6545..2e5a28a 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
@@ -40,7 +40,7 @@
* @return the roles read
*/
@Nullable
- RolesState readAsUser(@NonNull UserHandle user);
+ RolesState readForUser(@NonNull UserHandle user);
/**
* Write the roles to persistence.
@@ -50,7 +50,7 @@
* @param roles the roles to write
* @param user the user to write for
*/
- void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user);
+ void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user);
/**
* Delete the roles from persistence.
@@ -59,7 +59,7 @@
*
* @param user the user to delete for
*/
- void deleteAsUser(@NonNull UserHandle user);
+ void deleteForUser(@NonNull UserHandle user);
/**
* Create a new instance of {@link RolesPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
index 2346c11..f66257f 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
@@ -65,7 +65,7 @@
@Nullable
@Override
- public RolesState readAsUser(@NonNull UserHandle user) {
+ public RolesState readForUser(@NonNull UserHandle user) {
File file = getFile(user);
try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
XmlPullParser parser = Xml.newPullParser();
@@ -146,7 +146,7 @@
}
@Override
- public void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user) {
+ public void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user) {
File file = getFile(user);
AtomicFile atomicFile = new AtomicFile(file);
FileOutputStream outputStream = null;
@@ -205,7 +205,7 @@
}
@Override
- public void deleteAsUser(@NonNull UserHandle user) {
+ public void deleteForUser(@NonNull UserHandle user) {
getFile(user).delete();
}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesState.java b/apex/permission/service/java/com/android/role/persistence/RolesState.java
index 7da9d11..f61efa0 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesState.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesState.java
@@ -22,6 +22,7 @@
import android.annotation.SystemApi.Client;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -50,6 +51,13 @@
@NonNull
private final Map<String, Set<String>> mRoles;
+ /**
+ * Create a new instance of this class.
+ *
+ * @param version the version of the roles
+ * @param packagesHash the hash of all packages in the system
+ * @param roles the roles
+ */
public RolesState(int version, @Nullable String packagesHash,
@NonNull Map<String, Set<String>> roles) {
mVersion = version;
@@ -57,17 +65,51 @@
mRoles = roles;
}
+ /**
+ * Get the version of the roles.
+ *
+ * @return the version of the roles
+ */
public int getVersion() {
return mVersion;
}
+ /**
+ * Get the hash of all packages in the system.
+ *
+ * @return the hash of all packages in the system
+ */
@Nullable
public String getPackagesHash() {
return mPackagesHash;
}
+ /**
+ * Get the roles.
+ *
+ * @return the roles
+ */
@NonNull
public Map<String, Set<String>> getRoles() {
return mRoles;
}
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+ RolesState that = (RolesState) object;
+ return mVersion == that.mVersion
+ && Objects.equals(mPackagesHash, that.mPackagesHash)
+ && Objects.equals(mRoles, that.mRoles);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mVersion, mPackagesHash, mRoles);
+ }
}
diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index dc61f2ae..c84627d 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -54,6 +54,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -102,9 +103,6 @@
private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener();
private final OnAlarmListener mPullingAlarmListener = new PullingAlarmListener();
private final OnAlarmListener mPeriodicAlarmListener = new PeriodicAlarmListener();
- private final BroadcastReceiver mAppUpdateReceiver;
- private final BroadcastReceiver mUserUpdateReceiver;
- private final ShutdownEventReceiver mShutdownEventReceiver;
private StatsManagerService mStatsManagerService;
@@ -118,27 +116,6 @@
super();
mContext = context;
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- mAppUpdateReceiver = new AppUpdateReceiver();
- mUserUpdateReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
- return;
- }
- try {
- // Pull the latest state of UID->app name, version mapping.
- // Needed since the new user basically has a version of every app.
- informAllUidsLocked(context);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
- forgetEverythingLocked();
- }
- }
- }
- };
- mShutdownEventReceiver = new ShutdownEventReceiver();
if (DEBUG) Log.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
@@ -162,9 +139,18 @@
return ret;
}
- // Assumes that sStatsdLock is held.
- @GuardedBy("sStatsdLock")
- private void informAllUidsLocked(Context context) throws RemoteException {
+ /**
+ * Non-blocking call to retrieve a reference to statsd
+ *
+ * @return IStatsd object if statsd is ready, null otherwise.
+ */
+ private static IStatsd getStatsdNonblocking() {
+ synchronized (sStatsdLock) {
+ return sStatsd;
+ }
+ }
+
+ private static void informAllUidsLocked(Context context) throws RemoteException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
PackageManager pm = context.getPackageManager();
final List<UserHandle> users = um.getUserHandles(true);
@@ -273,7 +259,6 @@
if (!replacing) {
// Don't bother sending an update if we're right about to get another
// intent for the new version that's added.
- PackageManager pm = context.getPackageManager();
String app = intent.getData().getSchemeSpecificPart();
sStatsd.informOnePackageRemoved(app, uid);
}
@@ -303,23 +288,43 @@
}
}
- public final static class AnomalyAlarmListener implements OnAlarmListener {
+ private static final class UserUpdateReceiver extends BroadcastReceiver {
@Override
- public void onAlarm() {
- Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
- + System.currentTimeMillis() + "ms.");
+ public void onReceive(Context context, Intent intent) {
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
return;
}
try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informAnomalyAlarmFired();
+ // Pull the latest state of UID->app name, version mapping.
+ // Needed since the new user basically has a version of every app.
+ informAllUidsLocked(context);
} catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+ Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
}
}
+ }
+ }
+
+ public static final class AnomalyAlarmListener implements OnAlarmListener {
+ @Override
+ public void onAlarm() {
+ if (DEBUG) {
+ Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+ + System.currentTimeMillis() + "ms.");
+ }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ statsd.informAnomalyAlarmFired();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+ }
// AlarmManager releases its own wakelock here.
}
}
@@ -330,17 +335,16 @@
if (DEBUG) {
Log.d(TAG, "Time to poll something.");
}
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
- return;
- }
- try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informPollAlarmFired();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
- }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ statsd.informPollAlarmFired();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
}
}
}
@@ -351,17 +355,16 @@
if (DEBUG) {
Log.d(TAG, "Time to trigger periodic alarm.");
}
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
- return;
- }
- try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informAlarmForSubscriberTriggeringFired();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
- }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ statsd.informAlarmForSubscriberTriggeringFired();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
}
// AlarmManager releases its own wakelock here.
}
@@ -379,17 +382,19 @@
return;
}
- Log.i(TAG, "StatsCompanionService noticed a shutdown.");
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
- return;
- }
- try {
- sStatsd.informDeviceShutdown();
- } catch (Exception e) {
- Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
- }
+ if (DEBUG) {
+ Log.i(TAG, "StatsCompanionService noticed a shutdown.");
+ }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
+ return;
+ }
+ try {
+ // two way binder call
+ statsd.informDeviceShutdown();
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
}
}
}
@@ -515,7 +520,7 @@
}
}
- @Override
+ @Override // Binder call
public void triggerUidSnapshot() {
StatsCompanion.enforceStatsdCallingUid();
synchronized (sStatsdLock) {
@@ -525,7 +530,7 @@
} catch (RemoteException e) {
Log.e(TAG, "Failed to trigger uid snapshot.", e);
} finally {
- restoreCallingIdentity(token);
+ Binder.restoreCallingIdentity(token);
}
}
}
@@ -539,15 +544,28 @@
// Statsd related code
/**
- * Fetches the statsd IBinder service.
- * Note: This should only be called from sayHiToStatsd. All other clients should use the cached
- * sStatsd with a null check.
+ * Fetches the statsd IBinder service. This is a blocking call.
+ * Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use
+ * the cached sStatsd via {@link #getStatsdNonblocking()}.
*/
- private static IStatsd fetchStatsdService() {
- return IStatsd.Stub.asInterface(StatsFrameworkInitializer
- .getStatsServiceManager()
- .getStatsdServiceRegisterer()
- .get());
+ private IStatsd fetchStatsdService(StatsdDeathRecipient deathRecipient) {
+ synchronized (sStatsdLock) {
+ if (sStatsd == null) {
+ sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
+ .getStatsServiceManager()
+ .getStatsdServiceRegisterer()
+ .get());
+ if (sStatsd != null) {
+ try {
+ sStatsd.asBinder().linkToDeath(deathRecipient, /* flags */ 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed");
+ statsdNotReadyLocked();
+ }
+ }
+ }
+ return sStatsd;
+ }
}
/**
@@ -567,67 +585,84 @@
* statsd.
*/
private void sayHiToStatsd() {
- synchronized (sStatsdLock) {
- if (sStatsd != null) {
- Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
- new IllegalStateException(
- "sStatsd is not null when being fetched"));
- return;
- }
- sStatsd = fetchStatsdService();
- if (sStatsd == null) {
- Log.i(TAG,
- "Could not yet find statsd to tell it that StatsCompanion is "
- + "alive.");
- return;
- }
- mStatsManagerService.statsdReady(sStatsd);
- if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+ if (getStatsdNonblocking() != null) {
+ Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
+ new IllegalStateException(
+ "sStatsd is not null when being fetched"));
+ return;
+ }
+ StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient();
+ IStatsd statsd = fetchStatsdService(deathRecipient);
+ if (statsd == null) {
+ Log.i(TAG,
+ "Could not yet find statsd to tell it that StatsCompanion is "
+ + "alive.");
+ return;
+ }
+ mStatsManagerService.statsdReady(statsd);
+ if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+ try {
+ statsd.statsCompanionReady();
+
+ cancelAnomalyAlarm();
+ cancelPullingAlarm();
+
+ BroadcastReceiver appUpdateReceiver = new AppUpdateReceiver();
+ BroadcastReceiver userUpdateReceiver = new UserUpdateReceiver();
+ BroadcastReceiver shutdownEventReceiver = new ShutdownEventReceiver();
+
+ // Setup broadcast receiver for updates.
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null);
+
+ // Setup receiver for user initialize (which happens once for a new user)
+ // and
+ // if a user is removed.
+ filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null);
+
+ // Setup receiver for device reboots or shutdowns.
+ filter = new IntentFilter(Intent.ACTION_REBOOT);
+ filter.addAction(Intent.ACTION_SHUTDOWN);
+ mContext.registerReceiverForAllUsers(
+ shutdownEventReceiver, filter, null, null);
+
+ // Only add the receivers if the registration is successful.
+ deathRecipient.addRegisteredBroadcastReceivers(
+ List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver));
+
+ final long token = Binder.clearCallingIdentity();
try {
- sStatsd.statsCompanionReady();
- // If the statsCompanionReady two-way binder call returns, link to statsd.
- try {
- sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
- } catch (RemoteException e) {
- Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
- forgetEverythingLocked();
- }
- // Setup broadcast receiver for updates.
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mContext.registerReceiverForAllUsers(mAppUpdateReceiver, filter, null, null);
-
- // Setup receiver for user initialize (which happens once for a new user)
- // and
- // if a user is removed.
- filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
- filter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverForAllUsers(mUserUpdateReceiver, filter, null, null);
-
- // Setup receiver for device reboots or shutdowns.
- filter = new IntentFilter(Intent.ACTION_REBOOT);
- filter.addAction(Intent.ACTION_SHUTDOWN);
- mContext.registerReceiverForAllUsers(
- mShutdownEventReceiver, filter, null, null);
- final long token = Binder.clearCallingIdentity();
- try {
- // Pull the latest state of UID->app name, version mapping when
- // statsd starts.
- informAllUidsLocked(mContext);
- } finally {
- restoreCallingIdentity(token);
- }
- Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
- forgetEverythingLocked();
+ // Pull the latest state of UID->app name, version mapping when
+ // statsd starts.
+ informAllUidsLocked(mContext);
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
+ Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
}
}
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
+
+ private List<BroadcastReceiver> mReceiversToUnregister;
+
+ StatsdDeathRecipient() {
+ mReceiversToUnregister = new ArrayList<>();
+ }
+
+ public void addRegisteredBroadcastReceivers(List<BroadcastReceiver> receivers) {
+ synchronized (sStatsdLock) {
+ mReceiversToUnregister.addAll(receivers);
+ }
+ }
+
@Override
public void binderDied() {
Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
@@ -656,20 +691,18 @@
}
}
}
- forgetEverythingLocked();
+ // We only unregister in binder death becaseu receivers can only be unregistered
+ // once, or an IllegalArgumentException is thrown.
+ for (BroadcastReceiver receiver: mReceiversToUnregister) {
+ mContext.unregisterReceiver(receiver);
+ }
+ statsdNotReadyLocked();
}
}
}
- @GuardedBy("StatsCompanionService.sStatsdLock")
- private void forgetEverythingLocked() {
+ private void statsdNotReadyLocked() {
sStatsd = null;
- mContext.unregisterReceiver(mAppUpdateReceiver);
- mContext.unregisterReceiver(mUserUpdateReceiver);
- mContext.unregisterReceiver(mShutdownEventReceiver);
- cancelAnomalyAlarm();
- cancelPullingAlarm();
-
mStatsManagerService.statsdNotReady();
}
diff --git a/api/current.txt b/api/current.txt
index 15f10fa..a85d632 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4368,7 +4368,7 @@
method @Deprecated public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int);
method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int, @Nullable String, @Nullable String);
method @Nullable public static String permissionToOp(@NonNull String);
- method public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
+ method public void setOnOpNotedCallback(@Nullable java.util.concurrent.Executor, @Nullable android.app.AppOpsManager.OnOpNotedCallback);
method @Deprecated public int startOp(@NonNull String, int, @NonNull String);
method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
@@ -4424,14 +4424,6 @@
field public static final int WATCH_FOREGROUND_CHANGES = 1; // 0x1
}
- public abstract static class AppOpsManager.AppOpsCollector {
- ctor public AppOpsManager.AppOpsCollector();
- method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
- method public abstract void onAsyncNoted(@NonNull android.app.AsyncNotedAppOp);
- method public abstract void onNoted(@NonNull android.app.SyncNotedAppOp);
- method public abstract void onSelfNoted(@NonNull android.app.SyncNotedAppOp);
- }
-
public static interface AppOpsManager.OnOpActiveChangedListener {
method public void onOpActiveChanged(@NonNull String, int, @NonNull String, boolean);
}
@@ -4440,6 +4432,13 @@
method public void onOpChanged(String, String);
}
+ public abstract static class AppOpsManager.OnOpNotedCallback {
+ ctor public AppOpsManager.OnOpNotedCallback();
+ method public abstract void onAsyncNoted(@NonNull android.app.AsyncNotedAppOp);
+ method public abstract void onNoted(@NonNull android.app.SyncNotedAppOp);
+ method public abstract void onSelfNoted(@NonNull android.app.SyncNotedAppOp);
+ }
+
public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
method public static String getProcessName();
@@ -4591,7 +4590,7 @@
method @NonNull public String getMessage();
method @IntRange(from=0) public int getNotingUid();
method @NonNull public String getOp();
- method @IntRange(from=0) public long getTime();
+ method public long getTime();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AsyncNotedAppOp> CREATOR;
}
@@ -9467,7 +9466,7 @@
public static final class WifiDeviceFilter.Builder {
ctor public WifiDeviceFilter.Builder();
method @NonNull public android.companion.WifiDeviceFilter build();
- method @NonNull public android.companion.WifiDeviceFilter.Builder setBssid(@Nullable android.net.MacAddress);
+ method @NonNull public android.companion.WifiDeviceFilter.Builder setBssid(@NonNull android.net.MacAddress);
method @NonNull public android.companion.WifiDeviceFilter.Builder setBssidMask(@NonNull android.net.MacAddress);
method @NonNull public android.companion.WifiDeviceFilter.Builder setNamePattern(@Nullable java.util.regex.Pattern);
}
@@ -9882,7 +9881,7 @@
method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver);
method @Deprecated public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, int);
- method public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
+ method public void notifyChange(@NonNull java.util.Collection<android.net.Uri>, @Nullable android.database.ContentObserver, int);
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
@@ -10566,6 +10565,7 @@
field public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
field public static final String ACTION_ASSIST = "android.intent.action.ASSIST";
field public static final String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
+ field public static final String ACTION_AUTO_REVOKE_PERMISSIONS = "android.intent.action.AUTO_REVOKE_PERMISSIONS";
field public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
field public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
field public static final String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
@@ -10806,6 +10806,7 @@
field public static final String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
field public static final String EXTRA_TEXT = "android.intent.extra.TEXT";
field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+ field public static final String EXTRA_TIMEZONE = "time-zone";
field public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
field public static final String EXTRA_UID = "android.intent.extra.UID";
field public static final String EXTRA_USER = "android.intent.extra.USER";
@@ -11571,6 +11572,7 @@
method @NonNull public CharSequence getProfileSwitchingLabel(@NonNull android.os.UserHandle);
method @NonNull public java.util.List<android.os.UserHandle> getTargetUserProfiles();
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity);
+ method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
field public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED";
}
@@ -12972,11 +12974,11 @@
method @Deprecated public final void dispatchChange(boolean);
method public final void dispatchChange(boolean, @Nullable android.net.Uri);
method public final void dispatchChange(boolean, @Nullable android.net.Uri, int);
- method public final void dispatchChange(boolean, @NonNull Iterable<android.net.Uri>, int);
+ method public final void dispatchChange(boolean, @NonNull java.util.Collection<android.net.Uri>, int);
method public void onChange(boolean);
method public void onChange(boolean, @Nullable android.net.Uri);
method public void onChange(boolean, @Nullable android.net.Uri, int);
- method public void onChange(boolean, @NonNull Iterable<android.net.Uri>, int);
+ method public void onChange(boolean, @NonNull java.util.Collection<android.net.Uri>, int);
}
public interface CrossProcessCursor extends android.database.Cursor {
@@ -26448,14 +26450,14 @@
public static interface MediaParser.OutputConsumer {
method public void onSampleCompleted(int, long, int, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
- method public void onSampleData(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException;
- method public void onSeekMap(@NonNull android.media.MediaParser.SeekMap);
- method public void onTrackData(int, @NonNull android.media.MediaParser.TrackData);
- method public void onTracksFound(int);
+ method public void onSampleDataFound(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException;
+ method public void onSeekMapFound(@NonNull android.media.MediaParser.SeekMap);
+ method public void onTrackCountFound(int);
+ method public void onTrackDataFound(int, @NonNull android.media.MediaParser.TrackData);
}
public static final class MediaParser.SeekMap {
- method public long getDurationUs();
+ method public long getDurationMicros();
method @NonNull public android.util.Pair<android.media.MediaParser.SeekPoint,android.media.MediaParser.SeekPoint> getSeekPoints(long);
method public boolean isSeekable();
field public static final int UNKNOWN_DURATION = -2147483648; // 0x80000000
@@ -26464,7 +26466,7 @@
public static final class MediaParser.SeekPoint {
field @NonNull public static final android.media.MediaParser.SeekPoint START;
field public final long position;
- field public final long timeUs;
+ field public final long timeMicros;
}
public static interface MediaParser.SeekableInputReader extends android.media.MediaParser.InputReader {
@@ -36154,6 +36156,8 @@
method public static boolean isExternalStorageEmulated(@NonNull java.io.File);
method public static boolean isExternalStorageLegacy();
method public static boolean isExternalStorageLegacy(@NonNull java.io.File);
+ method public static boolean isExternalStorageManager();
+ method public static boolean isExternalStorageManager(@NonNull java.io.File);
method public static boolean isExternalStorageRemovable();
method public static boolean isExternalStorageRemovable(@NonNull java.io.File);
field public static String DIRECTORY_ALARMS;
@@ -45971,9 +45975,6 @@
field public static final int MISSED = 5; // 0x5
field public static final int OTHER = 9; // 0x9
field public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED";
- field public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
- field public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
- field public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
field public static final int REJECTED = 6; // 0x6
field public static final int REMOTE = 3; // 0x3
field public static final int RESTRICTED = 8; // 0x8
@@ -46300,7 +46301,6 @@
field public static final int DURATION_SHORT = 1; // 0x1
field public static final int DURATION_VERY_SHORT = 0; // 0x0
field public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
- field public static final String EXTRA_CALL_CREATED_TIME_MILLIS = "android.telecom.extra.CALL_CREATED_TIME_MILLIS";
field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
field public static final String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
field public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
@@ -46594,12 +46594,9 @@
field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
field public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
- field public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string";
- field public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = "5g_icon_display_grace_period_sec_int";
field public static final String KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrp_thresholds_int_array";
field public static final String KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrq_thresholds_int_array";
field public static final String KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY = "5g_nr_sssinr_thresholds_int_array";
- field public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long";
field public static final String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
@@ -46792,7 +46789,6 @@
field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
field public static final String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool";
field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
- field public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string";
field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
field public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = "show_forwarded_number_bool";
field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -47572,7 +47568,6 @@
method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
method @Nullable public android.telephony.CellIdentity getCellIdentity();
method public int getDomain();
- method public int getNrState();
method @Nullable public String getRegisteredPlmn();
method public int getTransportType();
method public boolean isRegistered();
@@ -47775,9 +47770,7 @@
method public boolean getIsManualSelection();
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
method public String getOperatorAlphaLong();
- method @Nullable public String getOperatorAlphaLongRaw();
method public String getOperatorAlphaShort();
- method @Nullable public String getOperatorAlphaShortRaw();
method public String getOperatorNumeric();
method public boolean getRoaming();
method public int getState();
@@ -48049,13 +48042,13 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>);
method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context);
method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
- method @Nullable public java.util.List<android.telephony.SubscriptionInfo> getActiveAndHiddenSubscriptionInfoList();
method public static int getActiveDataSubscriptionId();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getActiveSubscriptionInfoCount();
method public int getActiveSubscriptionInfoCountMax();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+ method @NonNull public java.util.List<android.telephony.SubscriptionInfo> getCompleteActiveSubscriptionInfoList();
method public static int getDefaultDataSubscriptionId();
method public static int getDefaultSmsSubscriptionId();
method public static int getDefaultSubscriptionId();
@@ -48218,6 +48211,7 @@
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isManualNetworkSelectionAllowed();
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isModemEnabledForSlot(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int isMultiSimSupported();
method public boolean isNetworkRoaming();
method public boolean isRttSupported();
@@ -48331,7 +48325,6 @@
field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
field public static final int PHONE_TYPE_CDMA = 2; // 0x2
field public static final int PHONE_TYPE_GSM = 1; // 0x1
- field public static final int PHONE_TYPE_IMS = 5; // 0x5
field public static final int PHONE_TYPE_NONE = 0; // 0x0
field public static final int PHONE_TYPE_SIP = 3; // 0x3
field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
@@ -55587,10 +55580,12 @@
}
public interface WindowInsetsController {
+ method public void addOnControllableInsetsChangedListener(@NonNull android.view.WindowInsetsController.OnControllableInsetsChangedListener);
method @NonNull public android.os.CancellationSignal controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
method public int getSystemBarsAppearance();
method public int getSystemBarsBehavior();
method public void hide(int);
+ method public void removeOnControllableInsetsChangedListener(@NonNull android.view.WindowInsetsController.OnControllableInsetsChangedListener);
method public void setSystemBarsAppearance(int, int);
method public void setSystemBarsBehavior(int);
method public void show(int);
@@ -55601,6 +55596,10 @@
field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
}
+ public static interface WindowInsetsController.OnControllableInsetsChangedListener {
+ method public void onControllableInsetsChanged(@NonNull android.view.WindowInsetsController, int);
+ }
+
public interface WindowManager extends android.view.ViewManager {
method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics();
method @Deprecated public android.view.Display getDefaultDisplay();
@@ -58000,7 +57999,7 @@
method @Deprecated public abstract void removeSessionCookie();
method public abstract void removeSessionCookies(@Nullable android.webkit.ValueCallback<java.lang.Boolean>);
method public abstract void setAcceptCookie(boolean);
- method public static void setAcceptFileSchemeCookies(boolean);
+ method @Deprecated public static void setAcceptFileSchemeCookies(boolean);
method public abstract void setAcceptThirdPartyCookies(android.webkit.WebView, boolean);
method public abstract void setCookie(String, String);
method public abstract void setCookie(String, String, @Nullable android.webkit.ValueCallback<java.lang.Boolean>);
@@ -58365,8 +58364,8 @@
method public abstract String getUserAgentString();
method public abstract void setAllowContentAccess(boolean);
method public abstract void setAllowFileAccess(boolean);
- method public abstract void setAllowFileAccessFromFileURLs(boolean);
- method public abstract void setAllowUniversalAccessFromFileURLs(boolean);
+ method @Deprecated public abstract void setAllowFileAccessFromFileURLs(boolean);
+ method @Deprecated public abstract void setAllowUniversalAccessFromFileURLs(boolean);
method public abstract void setAppCacheEnabled(boolean);
method @Deprecated public abstract void setAppCacheMaxSize(long);
method public abstract void setAppCachePath(String);
diff --git a/api/lint-baseline.txt b/api/lint-baseline.txt
index 569e838..83c78fe 100644
--- a/api/lint-baseline.txt
+++ b/api/lint-baseline.txt
@@ -15,6 +15,16 @@
ArrayReturn: android.content.ContentProviderOperation#resolveExtrasBackReferences(android.content.ContentProviderResult[], int) parameter #0:
+ArrayReturn: android.location.GnssAntennaInfo.SphericalCorrections#SphericalCorrections(double[][], double[][]) parameter #0:
+ Method parameter should be Collection<> (or subclass) instead of raw array; was `double[][]`
+ArrayReturn: android.location.GnssAntennaInfo.SphericalCorrections#SphericalCorrections(double[][], double[][]) parameter #1:
+ Method parameter should be Collection<> (or subclass) instead of raw array; was `double[][]`
+ArrayReturn: android.location.GnssAntennaInfo.SphericalCorrections#getCorrectionUncertaintiesArray():
+ Method should return Collection<> (or subclass) instead of raw array; was `double[][]`
+ArrayReturn: android.location.GnssAntennaInfo.SphericalCorrections#getCorrectionsArray():
+ Method should return Collection<> (or subclass) instead of raw array; was `double[][]`
+ArrayReturn: android.service.autofill.FillResponse.Builder#setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews, android.service.autofill.InlinePresentation) parameter #0:
+ Method parameter should be Collection<AutofillId> (or subclass) instead of raw array; was `android.view.autofill.AutofillId[]`
BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED:
@@ -453,8 +463,12 @@
+ExecutorRegistration: android.media.MediaRouter2#setOnGetControllerHintsListener(android.media.MediaRouter2.OnGetControllerHintsListener):
+ Registration methods should have overload that accepts delivery Executor: `setOnGetControllerHintsListener`
+
+
GenericException: android.content.res.loader.ResourcesProvider#finalize():
- Methods must not throw generic exceptions (`java.lang.Throwable`)
+
HiddenSuperclass: android.content.res.ColorStateList:
@@ -499,6 +513,30 @@
+IntentBuilderName: android.net.VpnManager#provisionVpnProfile(android.net.PlatformVpnProfile):
+ Methods creating an Intent should be named `create<Foo>Intent()`, was `provisionVpnProfile`
+
+
+KotlinOperator: android.media.AudioMetadata.Map#set(android.media.AudioMetadata.Key<T>, T):
+ Method can be invoked with an indexing operator from Kotlin: `set` (this is usually desirable; just make sure it makes sense for this type of object)
+KotlinOperator: android.media.AudioMetadata.ReadMap#get(android.media.AudioMetadata.Key<T>):
+ Method can be invoked with an indexing operator from Kotlin: `get` (this is usually desirable; just make sure it makes sense for this type of object)
+
+
+MethodNameUnits: android.media.MediaParser.SeekMap#getDurationMicros():
+ Returned time values are strongly encouraged to be in milliseconds unless you need the extra precision, was `getDurationMicros`
+
+
+MinMaxConstant: android.telephony.DataFailCause#MAX_ACCESS_PROBE:
+ If min/max could change in future, make them dynamic methods: android.telephony.DataFailCause#MAX_ACCESS_PROBE
+MinMaxConstant: android.telephony.DataFailCause#MAX_IPV4_CONNECTIONS:
+ If min/max could change in future, make them dynamic methods: android.telephony.DataFailCause#MAX_IPV4_CONNECTIONS
+MinMaxConstant: android.telephony.DataFailCause#MAX_IPV6_CONNECTIONS:
+ If min/max could change in future, make them dynamic methods: android.telephony.DataFailCause#MAX_IPV6_CONNECTIONS
+MinMaxConstant: android.telephony.DataFailCause#MAX_PPP_INACTIVITY_TIMER_EXPIRED:
+ If min/max could change in future, make them dynamic methods: android.telephony.DataFailCause#MAX_PPP_INACTIVITY_TIMER_EXPIRED
+
+
MissingNullability: android.app.AsyncNotedAppOp#equals(Object) parameter #0:
MissingNullability: android.app.AsyncNotedAppOp#writeToParcel(android.os.Parcel, int) parameter #0:
@@ -506,11 +544,11 @@
MissingNullability: android.app.SyncNotedAppOp#equals(Object) parameter #0:
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CHORASMIAN:
- Missing nullability on field `CHORASMIAN` in class `class android.icu.lang.UCharacter.UnicodeBlock`
+
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G:
- Missing nullability on field `CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G` in class `class android.icu.lang.UCharacter.UnicodeBlock`
+
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#DIVES_AKURU:
- Missing nullability on field `DIVES_AKURU` in class `class android.icu.lang.UCharacter.UnicodeBlock`
+
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS:
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#ELYMAIC:
@@ -556,14 +594,39 @@
MissingNullability: android.icu.util.VersionInfo#UNICODE_12_1:
MissingNullability: android.icu.util.VersionInfo#UNICODE_13_0:
- Missing nullability on field `UNICODE_13_0` in class `class android.icu.util.VersionInfo`
+
MissingNullability: android.media.MediaMetadataRetriever#getFrameAtTime(long, int, android.media.MediaMetadataRetriever.BitmapParams):
MissingNullability: android.media.MediaMetadataRetriever#getScaledFrameAtTime(long, int, int, int, android.media.MediaMetadataRetriever.BitmapParams):
-
MissingNullability: java.time.chrono.JapaneseEra#REIWA:
- Missing nullability on field `REIWA` in class `class java.time.chrono.JapaneseEra`
+
+
+
+NotCloseable: android.media.MediaCodec.GraphicBlock:
+ Classes that release resources (finalize()) should implement AutoClosable and CloseGuard: class android.media.MediaCodec.GraphicBlock
+NotCloseable: android.media.MediaCodec.LinearBlock:
+ Classes that release resources (finalize()) should implement AutoClosable and CloseGuard: class android.media.MediaCodec.LinearBlock
+NotCloseable: android.media.MediaParser:
+ Classes that release resources (release()) should implement AutoClosable and CloseGuard: class android.media.MediaParser
+NotCloseable: android.media.MediaRouter2.RoutingController:
+ Classes that release resources (release()) should implement AutoClosable and CloseGuard: class android.media.MediaRouter2.RoutingController
+NotCloseable: android.util.CloseGuard:
+ Classes that release resources (close()) should implement AutoClosable and CloseGuard: class android.util.CloseGuard
+NotCloseable: android.view.SurfaceControlViewHost:
+ Classes that release resources (release()) should implement AutoClosable and CloseGuard: class android.view.SurfaceControlViewHost
+
+
+OnNameExpected: android.app.admin.DevicePolicyKeyguardService#dismiss():
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.service.controls.ControlsProviderService#createPublisherFor(java.util.List<java.lang.String>):
+ Methods implemented by developers should follow the on<Something> style, was `createPublisherFor`
+OnNameExpected: android.service.controls.ControlsProviderService#createPublisherForAllAvailable():
+ Methods implemented by developers should follow the on<Something> style, was `createPublisherForAllAvailable`
+OnNameExpected: android.service.controls.ControlsProviderService#createPublisherForSuggested():
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.service.controls.ControlsProviderService#performControlAction(String, android.service.controls.actions.ControlAction, java.util.function.Consumer<java.lang.Integer>):
+ Methods implemented by developers should follow the on<Something> style, was `performControlAction`
RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler):
@@ -1189,11 +1252,13 @@
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, java.util.concurrent.Executor, android.location.LocationListener):
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, java.util.concurrent.Executor, android.location.LocationListener):
+
-
+StreamFiles: android.content.res.loader.DirectoryAssetsProvider#DirectoryAssetsProvider(java.io.File):
+ Methods accepting `File` should also accept `FileDescriptor` or streams: constructor android.content.res.loader.DirectoryAssetsProvider(java.io.File)
StreamFiles: android.content.res.loader.DirectoryResourceLoader#DirectoryResourceLoader(java.io.File):
- Methods accepting `File` should also accept `FileDescriptor` or streams: constructor android.content.res.loader.DirectoryResourceLoader(java.io.File)
+
Todo: android.hardware.camera2.params.StreamConfigurationMap:
diff --git a/api/removed.txt b/api/removed.txt
index fb6d576..8537b21 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -69,6 +69,10 @@
package android.content {
+ public abstract class ContentResolver {
+ method @Deprecated public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
+ }
+
public abstract class Context {
method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public abstract java.io.File getSharedPreferencesPath(String);
diff --git a/api/system-current.txt b/api/system-current.txt
index 25f16d3..b7aa9da 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -79,6 +79,7 @@
field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER";
field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
+ field public static final String EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS = "android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS";
field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
@@ -231,6 +232,7 @@
field public static final String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
field public static final String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
field public static final String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
+ field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
@@ -2938,7 +2940,7 @@
public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
- method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void requestLights(@NonNull android.hardware.lights.LightsRequest);
}
public final class LightsRequest {
@@ -4985,7 +4987,7 @@
package android.media.tv.tuner.filter {
- public class AlpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class AlpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.AlpFilterConfiguration.Builder builder(@NonNull android.content.Context);
method public int getLengthType();
method public int getPacketType();
@@ -5000,10 +5002,11 @@
field public static final int PACKET_TYPE_SIGNALING = 4; // 0x4
}
- public static class AlpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.AlpFilterConfiguration.Builder> {
+ public static final class AlpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setLengthType(int);
method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setPacketType(int);
+ method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
}
public class AudioDescriptor {
@@ -5091,15 +5094,11 @@
method public abstract int getType();
}
- public abstract static class FilterConfiguration.Builder<T extends android.media.tv.tuner.filter.FilterConfiguration.Builder<T>> {
- method @NonNull public T setSettings(@Nullable android.media.tv.tuner.filter.Settings);
- }
-
public abstract class FilterEvent {
ctor public FilterEvent();
}
- public class IpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class IpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.IpFilterConfiguration.Builder builder(@NonNull android.content.Context);
method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
method public int getDstPort();
@@ -5109,11 +5108,12 @@
method public boolean isPassthrough();
}
- public static class IpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.IpFilterConfiguration.Builder> {
+ public static final class IpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstIpAddress(@NonNull byte[]);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstPort(int);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setPassthrough(boolean);
+ method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcIpAddress(@NonNull byte[]);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcPort(int);
}
@@ -5137,15 +5137,16 @@
method public boolean isSecureMemory();
}
- public class MmtpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class MmtpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder builder(@NonNull android.content.Context);
method public int getMmtpPacketId();
method public int getType();
}
- public static class MmtpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder> {
+ public static final class MmtpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder setMmtpPacketId(int);
+ method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
}
public class MmtpRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
@@ -5280,7 +5281,7 @@
field public static final long TIMESTAMP_UNAVAILABLE = -1L; // 0xffffffffffffffffL
}
- public class TlvFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class TlvFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.TlvFilterConfiguration.Builder builder(@NonNull android.content.Context);
method public int getPacketType();
method public int getType();
@@ -5293,21 +5294,23 @@
field public static final int PACKET_TYPE_SIGNALING = 254; // 0xfe
}
- public static class TlvFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.TlvFilterConfiguration.Builder> {
+ public static final class TlvFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setCompressedIpPacket(boolean);
method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setPacketType(int);
method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setPassthrough(boolean);
+ method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
}
- public class TsFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class TsFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.TsFilterConfiguration.Builder builder(@NonNull android.content.Context);
method public int getTpid();
method public int getType();
}
- public static class TsFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.TsFilterConfiguration.Builder> {
+ public static final class TsFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration build();
+ method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setTpid(int);
}
@@ -5617,8 +5620,8 @@
method public int getConstellation();
method public int getGuardInterval();
method public int getHierarchy();
- method public int getHpCodeRate();
- method public int getLpCodeRate();
+ method public int getHighPriorityCodeRate();
+ method public int getLowPriorityCodeRate();
method public int getPlpGroupId();
method public int getPlpId();
method public int getPlpMode();
@@ -5646,20 +5649,20 @@
field public static final int CODERATE_8_9 = 512; // 0x200
field public static final int CODERATE_AUTO = 1; // 0x1
field public static final int CODERATE_UNDEFINED = 0; // 0x0
+ field public static final int CONSTELLATION_16QAM = 4; // 0x4
+ field public static final int CONSTELLATION_256QAM = 16; // 0x10
+ field public static final int CONSTELLATION_64QAM = 8; // 0x8
field public static final int CONSTELLATION_AUTO = 1; // 0x1
- field public static final int CONSTELLATION_CONSTELLATION_16QAM = 4; // 0x4
- field public static final int CONSTELLATION_CONSTELLATION_256QAM = 16; // 0x10
- field public static final int CONSTELLATION_CONSTELLATION_64QAM = 8; // 0x8
- field public static final int CONSTELLATION_CONSTELLATION_QPSK = 2; // 0x2
+ field public static final int CONSTELLATION_QPSK = 2; // 0x2
field public static final int CONSTELLATION_UNDEFINED = 0; // 0x0
+ field public static final int GUARD_INTERVAL_19_128 = 64; // 0x40
+ field public static final int GUARD_INTERVAL_19_256 = 128; // 0x80
+ field public static final int GUARD_INTERVAL_1_128 = 32; // 0x20
+ field public static final int GUARD_INTERVAL_1_16 = 4; // 0x4
+ field public static final int GUARD_INTERVAL_1_32 = 2; // 0x2
+ field public static final int GUARD_INTERVAL_1_4 = 16; // 0x10
+ field public static final int GUARD_INTERVAL_1_8 = 8; // 0x8
field public static final int GUARD_INTERVAL_AUTO = 1; // 0x1
- field public static final int GUARD_INTERVAL_INTERVAL_19_128 = 64; // 0x40
- field public static final int GUARD_INTERVAL_INTERVAL_19_256 = 128; // 0x80
- field public static final int GUARD_INTERVAL_INTERVAL_1_128 = 32; // 0x20
- field public static final int GUARD_INTERVAL_INTERVAL_1_16 = 4; // 0x4
- field public static final int GUARD_INTERVAL_INTERVAL_1_32 = 2; // 0x2
- field public static final int GUARD_INTERVAL_INTERVAL_1_4 = 16; // 0x10
- field public static final int GUARD_INTERVAL_INTERVAL_1_8 = 8; // 0x8
field public static final int GUARD_INTERVAL_UNDEFINED = 0; // 0x0
field public static final int HIERARCHY_1_INDEPTH = 64; // 0x40
field public static final int HIERARCHY_1_NATIVE = 4; // 0x4
@@ -5694,8 +5697,8 @@
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setGuardInterval(int);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHierarchy(int);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHighPriority(boolean);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHpCodeRate(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setLpCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHighPriorityCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setLowPriorityCodeRate(int);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setMiso(boolean);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpGroupId(int);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpId(int);
@@ -7155,7 +7158,7 @@
method @NonNull public java.util.List<android.net.MacAddress> getBlockedClientList();
method public int getChannel();
method public int getMaxNumberOfClients();
- method public int getShutdownTimeoutMillis();
+ method public long getShutdownTimeoutMillis();
method public boolean isAutoShutdownEnabled();
method public boolean isClientControlByUserEnabled();
method @Nullable public android.net.wifi.WifiConfiguration toWifiConfiguration();
@@ -7169,16 +7172,17 @@
ctor public SoftApConfiguration.Builder();
ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration);
method @NonNull public android.net.wifi.SoftApConfiguration build();
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder enableClientControlByUser(boolean);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAllowedClientList(@NonNull java.util.List<android.net.MacAddress>);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAutoShutdownEnabled(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBlockedClientList(@NonNull java.util.List<android.net.MacAddress>);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientList(@NonNull java.util.List<android.net.MacAddress>, @NonNull java.util.List<android.net.MacAddress>);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientControlByUserEnabled(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(@IntRange(from=0) int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(@IntRange(from=0) long);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
}
@@ -7239,7 +7243,6 @@
field @Deprecated public int numScorerOverride;
field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
field @Deprecated public boolean requirePmf;
- field @Deprecated @Nullable public String saePasswordId;
field @Deprecated public boolean shared;
field @Deprecated public boolean useExternalScores;
}
@@ -7327,17 +7330,17 @@
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK}) public void disableEphemeralNetwork(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset();
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
- method @Nullable @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public String getCountryCode();
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCountryCode();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.Network getCurrentNetwork();
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
method @NonNull @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.Map<android.net.wifi.WifiNetworkSuggestion,java.util.List<android.net.wifi.ScanResult>> getMatchingScanResults(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, @Nullable java.util.List<android.net.wifi.ScanResult>);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
- method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener);
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
@@ -7458,9 +7461,9 @@
method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry);
}
- public static interface WifiManager.ScoreChangeCallback {
- method public void onScoreChange(int, int);
- method public void onTriggerUpdateOfWifiUsabilityStats(int);
+ public static interface WifiManager.ScoreUpdateObserver {
+ method public void notifyScoreUpdate(int, int);
+ method public void triggerUpdateOfWifiUsabilityStats(int);
}
public static interface WifiManager.SoftApCallback {
@@ -7480,9 +7483,9 @@
}
public static interface WifiManager.WifiConnectedNetworkScorer {
- method public void setScoreChangeCallback(@NonNull android.net.wifi.WifiManager.ScoreChangeCallback);
- method public void start(int);
- method public void stop(int);
+ method public void onSetScoreUpdateObserver(@NonNull android.net.wifi.WifiManager.ScoreUpdateObserver);
+ method public void onStart(int);
+ method public void onStop(int);
}
public final class WifiMigration {
@@ -7984,7 +7987,7 @@
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public void requestPersistentGroupInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setDeviceName(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull String, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
- method @RequiresPermission(allOf={android.Manifest.permission.CONNECTIVITY_INTERNAL, android.Manifest.permission.CONFIGURE_WIFI_DISPLAY}) public void setMiracastMode(int);
+ method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setMiracastMode(int);
method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setWfdInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pWfdInfo, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setWifiP2pChannels(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void startListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
@@ -8943,7 +8946,7 @@
}
public final class PermissionManager {
- method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public int getRuntimePermissionsVersion();
+ method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledCarrierApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledImsServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
@@ -8951,7 +8954,7 @@
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
}
@@ -9065,18 +9068,6 @@
package android.provider {
- public class BlockedNumberContract {
- field public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
- field public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
- field public static final String RES_BLOCK_STATUS = "block_status";
- field public static final int STATUS_BLOCKED_IN_LIST = 1; // 0x1
- field public static final int STATUS_BLOCKED_NOT_IN_CONTACTS = 5; // 0x5
- field public static final int STATUS_BLOCKED_PAYPHONE = 4; // 0x4
- field public static final int STATUS_BLOCKED_RESTRICTED = 2; // 0x2
- field public static final int STATUS_BLOCKED_UNKNOWN_NUMBER = 3; // 0x3
- field public static final int STATUS_NOT_BLOCKED = 0; // 0x0
- }
-
@Deprecated public static final class ContactsContract.MetadataSync implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncColumns {
field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
@@ -9434,7 +9425,6 @@
public static final class Telephony.Carriers implements android.provider.BaseColumns {
field public static final String APN_SET_ID = "apn_set_id";
- field @Deprecated public static final String BEARER_BITMASK = "bearer_bitmask";
field public static final int CARRIER_EDITED = 4; // 0x4
field @NonNull public static final android.net.Uri DPC_URI;
field public static final String EDITED_STATUS = "edited";
@@ -9443,11 +9433,6 @@
field public static final String MODEM_PERSIST = "modem_cognitive";
field public static final String MTU = "mtu";
field public static final int NO_APN_SET_ID = 0; // 0x0
- field public static final String PROFILE_ID = "profile_id";
- field public static final String SKIP_464XLAT = "skip_464xlat";
- field public static final int SKIP_464XLAT_DEFAULT = -1; // 0xffffffff
- field public static final int SKIP_464XLAT_DISABLE = 0; // 0x0
- field public static final int SKIP_464XLAT_ENABLE = 1; // 0x1
field public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
field public static final int UNEDITED = 0; // 0x0
field public static final int USER_DELETED = 2; // 0x2
@@ -9973,7 +9958,7 @@
}
public static final class DataLoaderService.FileSystemConnector {
- method public void writeData(@NonNull String, long, long, @NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void writeData(@NonNull String, long, long, @NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
}
}
@@ -10651,14 +10636,7 @@
}
public final class PhoneAccount implements android.os.Parcelable {
- field public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 128; // 0x80
- field public static final int CAPABILITY_EMERGENCY_PREFERRED = 8192; // 0x2000
- field public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 512; // 0x200
field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
- field public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE = "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
- field public static final String EXTRA_PLAY_CALL_RECORDING_TONE = "android.telecom.extra.PLAY_CALL_RECORDING_TONE";
- field public static final String EXTRA_SORT_ORDER = "android.telecom.extra.SORT_ORDER";
- field public static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK = "android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK";
}
public static class PhoneAccount.Builder {
@@ -10744,20 +10722,13 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
- field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED";
- field public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
field public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1; // 0x1
field public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; // 0x2
field public static final int CALL_SOURCE_UNSPECIFIED = 0; // 0x0
field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
- field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
- field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
- field public static final String EXTRA_CURRENT_TTY_MODE = "android.telecom.extra.CURRENT_TTY_MODE";
field public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL = "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL";
- field public static final String EXTRA_TTY_PREFERRED_MODE = "android.telecom.extra.TTY_PREFERRED_MODE";
- field public static final String EXTRA_UNKNOWN_CALL_HANDLE = "android.telecom.extra.UNKNOWN_CALL_HANDLE";
field public static final int TTY_MODE_FULL = 1; // 0x1
field public static final int TTY_MODE_HCO = 2; // 0x2
field public static final int TTY_MODE_OFF = 0; // 0x0
@@ -10911,19 +10882,6 @@
method @NonNull public java.util.List<android.telephony.CbGeoUtils.LatLng> getVertices();
}
- public final class CdmaEriInformation implements android.os.Parcelable {
- method public int describeContents();
- method public int getEriIconIndex();
- method public int getEriIconMode();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CdmaEriInformation> CREATOR;
- field public static final int ERI_FLASH = 2; // 0x2
- field public static final int ERI_ICON_MODE_FLASH = 1; // 0x1
- field public static final int ERI_ICON_MODE_NORMAL = 0; // 0x0
- field public static final int ERI_OFF = 1; // 0x1
- field public static final int ERI_ON = 0; // 0x0
- }
-
public class CellBroadcastIntents {
method public static void sendSmsCbReceivedBroadcast(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.telephony.SmsCbMessage, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, int);
field public static final String ACTION_AREA_INFO_UPDATED = "android.telephony.action.AREA_INFO_UPDATED";
@@ -10981,7 +10939,6 @@
public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
- method public boolean isUsingCarrierAggregation();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR;
}
@@ -11219,19 +11176,6 @@
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
}
- public final class PinResult implements android.os.Parcelable {
- ctor public PinResult(int, int);
- method public int describeContents();
- method public int getAttemptsRemaining();
- method @NonNull public static android.telephony.PinResult getDefaultFailedResult();
- method public int getType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PinResult> CREATOR;
- field public static final int PIN_RESULT_TYPE_FAILURE = 2; // 0x2
- field public static final int PIN_RESULT_TYPE_INCORRECT = 1; // 0x1
- field public static final int PIN_RESULT_TYPE_SUCCESS = 0; // 0x0
- }
-
public final class PreciseCallState implements android.os.Parcelable {
ctor public PreciseCallState(int, int, int, int, int);
method public int describeContents();
@@ -11362,12 +11306,9 @@
public class ServiceState implements android.os.Parcelable {
method public void fillInNotifierBundle(@NonNull android.os.Bundle);
method public int getDataNetworkType();
- method public int getDataRegistrationState();
- method public boolean getDataRoamingFromRegistration();
method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int);
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int);
- method public int getNrFrequencyRange();
method @NonNull public static android.telephony.ServiceState newFromBundle(@NonNull android.os.Bundle);
field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2
field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3
@@ -11619,7 +11560,6 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CdmaEriInformation getCdmaEriInformation();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
@@ -11632,7 +11572,6 @@
method @Deprecated public boolean getDataEnabled();
method @Deprecated public boolean getDataEnabled(int);
method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean);
- method @NonNull public static String getDefaultSimCountryIso();
method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
@@ -11674,7 +11613,6 @@
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isLteCdmaEvdoGsmWcdmaEnabled();
- method public boolean isModemEnabledForSlot(int);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
@@ -11727,10 +11665,8 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoiceActivationState(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void shutdownAllRadios();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPin(String);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult supplyPinReportPinResult(@NonNull String);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPuk(String, String);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult supplyPukReportPinResult(@NonNull String, @NonNull String);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
@@ -11823,7 +11759,6 @@
field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L
field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L
field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L
- field public static final int PHONE_TYPE_THIRD_PARTY = 4; // 0x4
field public static final int RADIO_POWER_OFF = 0; // 0x0
field public static final int RADIO_POWER_ON = 1; // 0x1
field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
@@ -11903,23 +11838,6 @@
package android.telephony.data {
- public class ApnSetting implements android.os.Parcelable {
- method @NonNull public static String getApnTypesStringFromBitmask(int);
- field public static final String TYPE_ALL_STRING = "*";
- field public static final String TYPE_CBS_STRING = "cbs";
- field public static final String TYPE_DEFAULT_STRING = "default";
- field public static final String TYPE_DUN_STRING = "dun";
- field public static final String TYPE_EMERGENCY_STRING = "emergency";
- field public static final String TYPE_FOTA_STRING = "fota";
- field public static final String TYPE_HIPRI_STRING = "hipri";
- field public static final String TYPE_IA_STRING = "ia";
- field public static final String TYPE_IMS_STRING = "ims";
- field public static final String TYPE_MCX_STRING = "mcx";
- field public static final String TYPE_MMS_STRING = "mms";
- field public static final String TYPE_SUPL_STRING = "supl";
- field public static final String TYPE_XCAP_STRING = "xcap";
- }
-
public final class DataCallResponse implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 07b8969..23e2499 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -11,6 +11,12 @@
public class AppOpsManager {
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable int[]);
+ method @Deprecated public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
+ }
+
+ @Deprecated public abstract static class AppOpsManager.AppOpsCollector extends android.app.AppOpsManager.OnOpNotedCallback {
+ ctor public AppOpsManager.AppOpsCollector();
+ method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
}
public class Notification implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 9d284b5..4f4c82b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -21,6 +21,7 @@
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
+ field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
@@ -427,6 +428,7 @@
method public boolean isBlockableSystem();
method public boolean isImportanceLockedByCriticalDeviceFunction();
method public boolean isImportanceLockedByOEM();
+ method public void lockFields(int);
method public void setBlockableSystem(boolean);
method public void setDeleted(boolean);
method public void setFgServiceShown(boolean);
@@ -434,6 +436,7 @@
method public void setImportanceLockedByOEM(boolean);
method public void setImportantConversation(boolean);
method public void setOriginalImportance(int);
+ field public static final int USER_LOCKED_SOUND = 32; // 0x20
}
public final class NotificationChannelGroup implements android.os.Parcelable {
@@ -1278,7 +1281,7 @@
public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
- method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void requestLights(@NonNull android.hardware.lights.LightsRequest);
}
public final class LightsRequest {
@@ -2811,9 +2814,9 @@
}
public final class PermissionManager {
- method @IntRange(from=0) @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public int getRuntimePermissionsVersion();
+ method @IntRange(from=0) @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
- method @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
+ method @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
}
public static final class PermissionManager.SplitPermissionInfo {
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index f84e4b5..8f5e49d 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -113,7 +113,7 @@
Status Idmap2Service::createIdmap(const std::string& target_apk_path,
const std::string& overlay_apk_path, int32_t fulfilled_policies,
bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
- std::unique_ptr<std::string>* _aidl_return) {
+ aidl::nullable<std::string>* _aidl_return) {
assert(_aidl_return);
SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path;
_aidl_return->reset(nullptr);
@@ -155,7 +155,7 @@
return error("failed to write to idmap path " + idmap_path);
}
- *_aidl_return = std::make_unique<std::string>(idmap_path);
+ *_aidl_return = aidl::make_nullable<std::string>(idmap_path);
return ok();
}
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index 94d2af4..b6f5136 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -19,9 +19,7 @@
#include <android-base/unique_fd.h>
#include <binder/BinderService.h>
-
-#include <memory>
-#include <string>
+#include <binder/Nullable.h>
#include "android/os/BnIdmap2.h"
@@ -46,7 +44,7 @@
binder::Status createIdmap(const std::string& target_apk_path,
const std::string& overlay_apk_path, int32_t fulfilled_policies,
bool enforce_overlayable, int32_t user_id,
- std::unique_ptr<std::string>* _aidl_return) override;
+ aidl::nullable<std::string>* _aidl_return) override;
};
} // namespace android::os
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index bd6ca47..33bfe51 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -113,8 +113,8 @@
"libbase",
"libcutils",
"libprotoutil",
- "libstatslog",
"libstatsmetadata",
+ "libstatslog_statsd",
"libsysutils",
"libutils",
],
@@ -171,6 +171,37 @@
],
}
+genrule {
+ name: "statslog_statsd.h",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_statsd.h --module statsd --namespace android,os,statsd,util",
+ out: [
+ "statslog_statsd.h",
+ ],
+}
+
+genrule {
+ name: "statslog_statsd.cpp",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_statsd.cpp --module statsd --namespace android,os,statsd,util --importHeader statslog_statsd.h",
+ out: [
+ "statslog_statsd.cpp",
+ ],
+}
+
+cc_library_static {
+ name: "libstatslog_statsd",
+ generated_sources: ["statslog_statsd.cpp"],
+ generated_headers: ["statslog_statsd.h"],
+ export_generated_headers: ["statslog_statsd.h"],
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ ],
+ shared_libs: [
+ "libstatssocket",
+ ]
+}
// =========
// statsd
@@ -300,6 +331,7 @@
static_libs: [
"libgmock",
"libplatformprotos",
+ "libstatslog", //TODO(b/150976524): remove this when the tests no longer hardcode atoms.
"libstatssocket_private",
],
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 649c004..69b9fc7 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -34,7 +34,7 @@
#include "state/StateManager.h"
#include "stats_log_util.h"
#include "stats_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
#include "storage/StorageManager.h"
using namespace android;
@@ -287,17 +287,17 @@
int64_t firstId = trainInfo->experimentIds.at(0);
auto& ids = trainInfo->experimentIds;
switch (trainInfo->status) {
- case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
+ case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
if (find(ids.begin(), ids.end(), firstId + 1) == ids.end()) {
ids.push_back(firstId + 1);
}
break;
- case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
+ case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
if (find(ids.begin(), ids.end(), firstId + 2) == ids.end()) {
ids.push_back(firstId + 2);
}
break;
- case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
+ case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
if (find(ids.begin(), ids.end(), firstId + 3) == ids.end()) {
ids.push_back(firstId + 3);
}
@@ -366,13 +366,13 @@
int64_t firstId = trainInfoOnDisk.experimentIds[0];
auto& ids = trainInfoOnDisk.experimentIds;
switch (rollbackTypeIn) {
- case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
+ case android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
if (find(ids.begin(), ids.end(), firstId + 4) == ids.end()) {
ids.push_back(firstId + 4);
}
StorageManager::writeTrainInfo(trainInfoOnDisk);
break;
- case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
+ case android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
if (find(ids.begin(), ids.end(), firstId + 5) == ids.end()) {
ids.push_back(firstId + 5);
}
@@ -405,13 +405,13 @@
// Hard-coded logic to update train info on disk and fill in any information
// this log event may be missing.
- if (event->GetTagId() == android::util::BINARY_PUSH_STATE_CHANGED) {
+ if (event->GetTagId() == android::os::statsd::util::BINARY_PUSH_STATE_CHANGED) {
onBinaryPushStateChangedEventLocked(event);
}
// Hard-coded logic to update experiment ids on disk for certain rollback
// types and fill the rollback atom with experiment ids
- if (event->GetTagId() == android::util::WATCHDOG_ROLLBACK_OCCURRED) {
+ if (event->GetTagId() == android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED) {
onWatchdogRollbackOccurredLocked(event);
}
@@ -429,7 +429,7 @@
// Hard-coded logic to update the isolated uid's in the uid-map.
// The field numbers need to be currently updated by hand with atoms.proto
- if (event->GetTagId() == android::util::ISOLATED_UID_CHANGED) {
+ if (event->GetTagId() == android::os::statsd::util::ISOLATED_UID_CHANGED) {
onIsolatedUidChangedEventLocked(*event);
}
@@ -446,7 +446,7 @@
}
- if (event->GetTagId() != android::util::ISOLATED_UID_CHANGED) {
+ if (event->GetTagId() != android::os::statsd::util::ISOLATED_UID_CHANGED) {
// Map the isolated uid to host uid if necessary.
mapIsolatedUidToHostUidIfNecessaryLocked(event);
}
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index cd10457..07579bb 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -32,7 +32,7 @@
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <frameworks/base/cmds/statsd/src/uid_data.pb.h>
#include <private/android_filesystem_config.h>
-#include <statslog.h>
+#include <statslog_statsd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/system_properties.h>
@@ -767,7 +767,8 @@
}
if (good) {
dprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
- android::util::stats_write(android::util::APP_BREADCRUMB_REPORTED, uid, label, state);
+ android::os::statsd::util::stats_write(
+ android::os::statsd::util::APP_BREADCRUMB_REPORTED, uid, label, state);
} else {
print_cmd_help(out);
return UNKNOWN_ERROR;
@@ -1188,7 +1189,7 @@
Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) {
// Permission check not necessary as it's meant for applications to write to
// statsd.
- android::util::stats_write(util::APP_BREADCRUMB_REPORTED,
+ android::os::statsd::util::stats_write(android::os::statsd::util::APP_BREADCRUMB_REPORTED,
(int32_t) AIBinder_getCallingUid(), label,
state);
return Status::ok();
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
index 019a9f7..5722f92 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -23,7 +23,6 @@
#include "stats_util.h"
#include "storage/StorageManager.h"
-#include <statslog.h>
#include <time.h>
namespace android {
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 7ace44e..a21abbf 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -25,7 +25,7 @@
#include "subscriber/SubscriberReporter.h"
#include <inttypes.h>
-#include <statslog.h>
+#include <statslog_statsd.h>
#include <time.h>
namespace android {
@@ -235,8 +235,8 @@
StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id());
// TODO(b/110564268): This should also take in the const MetricDimensionKey& key?
- android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(),
- mConfigKey.GetId(), mAlert.id());
+ util::stats_write(util::ANOMALY_DETECTED, mConfigKey.GetUid(),
+ mConfigKey.GetId(), mAlert.id());
}
void AnomalyTracker::detectAndDeclareAnomaly(const int64_t& timestampNs,
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 80f9fea..56f2340 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -122,10 +122,10 @@
SettingChanged setting_changed = 41 [(module) = "framework"];
ActivityForegroundStateChanged activity_foreground_state_changed =
42 [(module) = "framework"];
- IsolatedUidChanged isolated_uid_changed = 43 [(module) = "framework"];
+ IsolatedUidChanged isolated_uid_changed = 43 [(module) = "framework", (module) = "statsd"];
PacketWakeupOccurred packet_wakeup_occurred = 44 [(module) = "framework"];
WallClockTimeShifted wall_clock_time_shifted = 45 [(module) = "framework"];
- AnomalyDetected anomaly_detected = 46;
+ AnomalyDetected anomaly_detected = 46 [(module) = "statsd"];
AppBreadcrumbReported app_breadcrumb_reported =
47 [(allow_from_any_uid) = true, (module) = "statsd"];
AppStartOccurred app_start_occurred = 48 [(module) = "framework"];
@@ -138,7 +138,7 @@
AppStartMemoryStateCaptured app_start_memory_state_captured = 55 [(module) = "framework"];
ShutdownSequenceReported shutdown_sequence_reported = 56 [(module) = "framework"];
BootSequenceReported boot_sequence_reported = 57;
- DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true];
+ DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true, (module) = "statsd"];
OverlayStateChanged overlay_state_changed = 59 [(module) = "framework"];
ForegroundServiceStateChanged foreground_service_state_changed
= 60 [(module) = "framework"];
@@ -166,7 +166,7 @@
LowMemReported low_mem_reported = 81 [(module) = "framework"];
GenericAtom generic_atom = 82;
KeyValuePairsAtom key_value_pairs_atom =
- 83 [(allow_from_any_uid) = true, (module) = "framework"];
+ 83 [(allow_from_any_uid) = true, (module) = "framework", (module) = "statsd"];
VibratorStateChanged vibrator_state_changed = 84 [(module) = "framework"];
DeferredJobStatsReported deferred_job_stats_reported = 85 [(module) = "framework"];
ThermalThrottlingStateChanged thermal_throttling = 86 [deprecated=true];
@@ -242,7 +242,8 @@
AdbConnectionChanged adb_connection_changed = 144 [(module) = "framework"];
SpeechDspStatReported speech_dsp_stat_reported = 145;
UsbContaminantReported usb_contaminant_reported = 146 [(module) = "framework"];
- WatchdogRollbackOccurred watchdog_rollback_occurred = 147 [(module) = "framework"];
+ WatchdogRollbackOccurred watchdog_rollback_occurred =
+ 147 [(module) = "framework", (module) = "statsd"];
BiometricSystemHealthIssueDetected biometric_system_health_issue_detected =
148 [(module) = "framework"];
BubbleUIChanged bubble_ui_changed = 149 [(module) = "sysui"];
@@ -401,7 +402,7 @@
}
// Pulled events will start at field 10000.
- // Next: 10076
+ // Next: 10080
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
@@ -412,7 +413,8 @@
SubsystemSleepState subsystem_sleep_state = 10005;
CpuTimePerFreq cpu_time_per_freq = 10008 [(module) = "framework"];
CpuTimePerUid cpu_time_per_uid = 10009 [(module) = "framework"];
- CpuTimePerUidFreq cpu_time_per_uid_freq = 10010 [(module) = "framework"];
+ CpuTimePerUidFreq cpu_time_per_uid_freq =
+ 10010 [(module) = "framework", (module) = "statsd"];
WifiActivityInfo wifi_activity_info = 10011 [(module) = "framework"];
ModemActivityInfo modem_activity_info = 10012 [(module) = "framework"];
BluetoothActivityInfo bluetooth_activity_info = 10007 [(module) = "framework"];
@@ -425,9 +427,9 @@
RemainingBatteryCapacity remaining_battery_capacity = 10019 [(module) = "framework"];
FullBatteryCapacity full_battery_capacity = 10020 [(module) = "framework"];
Temperature temperature = 10021 [(module) = "framework"];
- BinderCalls binder_calls = 10022 [(module) = "framework"];
+ BinderCalls binder_calls = 10022 [(module) = "framework", (module) = "statsd"];
BinderCallsExceptions binder_calls_exceptions = 10023 [(module) = "framework"];
- LooperStats looper_stats = 10024 [(module) = "framework"];
+ LooperStats looper_stats = 10024 [(module) = "framework", (module) = "statsd"];
DiskStats disk_stats = 10025 [(module) = "framework"];
DirectoryUsage directory_usage = 10026 [(module) = "framework"];
AppSize app_size = 10027 [(module) = "framework"];
@@ -455,7 +457,7 @@
NumFacesEnrolled num_faces_enrolled = 10048 [(module) = "framework"];
RoleHolder role_holder = 10049 [(module) = "framework"];
DangerousPermissionState dangerous_permission_state = 10050 [(module) = "framework"];
- TrainInfo train_info = 10051;
+ TrainInfo train_info = 10051 [(module) = "statsd"];
TimeZoneDataInfo time_zone_data_info = 10052 [(module) = "framework"];
ExternalStorageInfo external_storage_info = 10053 [(module) = "framework"];
GpuStatsGlobalInfo gpu_stats_global_info = 10054;
@@ -484,6 +486,10 @@
10073 [(module) = "framework"];
GnssStats gnss_stats = 10074 [(module) = "framework"];
AppFeaturesOps app_features_ops = 10075 [(module) = "framework"];
+ VoiceCallSession voice_call_session = 10076 [(module) = "telephony"];
+ VoiceCallRatUsage voice_call_rat_usage = 10077 [(module) = "telephony"];
+ SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
+ SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -4475,8 +4481,7 @@
* after an OTA.
*
* Logged from:
- * - system/core/fs_mgr/libsnapshot/snapshot.cpp
- * - system/core/fs_mgr/libsnapshot/snapshotctl.cpp
+ * - system/update_engine/cleanup_previous_update_action.cc
*/
message SnapshotMergeReported {
// Keep in sync with
@@ -8670,6 +8675,154 @@
}
/**
+ * Pulls information for a single voice call.
+ *
+ * Each pull creates multiple atoms, one for each call. The sequence is randomized when pulled.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/PersistPullers.java
+ */
+message VoiceCallSession {
+ // Bearer (IMS or CS) when the call started.
+ optional android.telephony.CallBearerEnum bearer_at_start = 1;
+
+ // Bearer (IMS or CS) when the call ended.
+ // The bearer may change during the call, e.g. due to SRVCC.
+ optional android.telephony.CallBearerEnum bearer_at_end = 2;
+
+ // Direction of the call (incoming or outgoing).
+ optional android.telephony.CallDirectionEnum direction = 3;
+
+ // Time spent setting up the call.
+ optional android.telephony.CallSetupDurationEnum setup_duration = 4;
+
+ // Whether the call ended before the setup was completed.
+ optional bool setup_failed = 5;
+
+ // IMS reason code or CS disconnect cause.
+ // For IMS, see: frameworks/base/telephony/java/android/telephony/ims/ImsReasonInfo.java
+ // For CS, see: frameworks/base/telephony/java/android/telephony/DisconnectCause.java
+ optional int32 disconnect_reason_code = 6;
+
+ // IMS extra code or CS precise disconnect cause.
+ // For IMS, this code is vendor-specific
+ // For CS, see: frameworks/base/telephony/java/android/telephony/PreciseDisconnectCause.java
+ optional int32 disconnect_extra_code = 7;
+
+ // IMS extra message or CS vendor cause.
+ optional string disconnect_extra_message = 8;
+
+ // Radio access technology (RAT) used when call started.
+ optional android.telephony.NetworkTypeEnum rat_at_start = 9;
+
+ // Radio access technology (RAT) used when call terminated.
+ optional android.telephony.NetworkTypeEnum rat_at_end = 10;
+
+ // Number of times RAT changed during the call.
+ optional int64 rat_switch_count = 11;
+
+ // A bitmask of all codecs used during the call.
+ // See: frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
+ optional int64 codec_bitmask = 12;
+
+ // Number of other calls going on during call setup, for the same SIM slot.
+ optional int32 concurrent_call_count_at_start = 13;
+
+ // Number of other calls going on during call termination, for the same SIM slot.
+ optional int32 concurrent_call_count_at_end = 14;
+
+ // Index of the SIM is used, 0 for single-SIM devices.
+ optional int32 sim_slot_index = 15;
+
+ // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
+ optional bool is_multi_sim = 16;
+
+ // Whether the call was made with an eSIM profile.
+ optional bool is_esim = 17;
+
+ // Carrier ID of the SIM card.
+ // See https://source.android.com/devices/tech/config/carrierid.
+ optional int32 carrier_id = 18;
+
+ // Whether an SRVCC has been completed successfully.
+ // SRVCC (CS fallback) should be recorded in the IMS call since there will be no more SRVCC
+ // events once the call is switched to CS.
+ optional bool srvcc_completed = 19;
+
+ // Number of SRVCC failures.
+ optional int64 srvcc_failure_count = 20;
+
+ // Number of SRVCC cancellations.
+ optional int64 srvcc_cancellation_count = 21;
+
+ // Whether the Real-Time Text (RTT) was ever used in the call.
+ optional bool rtt_enabled = 22;
+
+ // Whether this was an emergency call.
+ optional bool is_emergency = 23;
+
+ // Whether the call was performed while roaming.
+ optional bool is_roaming = 24;
+}
+
+/**
+ * Pulls voice call radio access technology (RAT) usage.
+ *
+ * Each pull creates multiple atoms, one for each carrier/RAT, the order of which is irrelevant to
+ * time. The atom will be skipped if not enough data is available.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/PersistPullers.java
+ */
+message VoiceCallRatUsage {
+ // Carrier ID (https://source.android.com/devices/tech/config/carrierid).
+ optional int32 carrier_id = 1;
+
+ // Radio access technology.
+ optional android.telephony.NetworkTypeEnum rat = 2;
+
+ // Total duration that voice calls spent on this carrier and RAT.
+ optional int64 total_duration_seconds = 3;
+
+ // Total number of calls using this carrier and RAT.
+ // A call is counted once even if it used the RAT multiple times.
+ optional int64 call_count = 4;
+}
+
+/**
+ * Pulls the number of active SIM slots and SIMs/eSIM profiles.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/NonPersistPullers.java
+ */
+message SimSlotState {
+ // Number of active SIM slots (both physical and eSIM profiles) in the device.
+ optional int32 active_slot_count = 1;
+
+ // Number of SIM cards (both physical and active eSIM profiles).
+ // This number is always equal to or less than the number of active SIM slots.
+ optional int32 sim_count = 2;
+
+ // Number of active eSIM profiles.
+ // This number is always equal to or less than the number of SIMs.
+ optional int32 esim_count = 3;
+}
+
+/**
+ * Pulls supported cellular radio access technologies.
+ *
+ * This atom reports the capabilities of the device, rather than the network it has access to.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/NonPersistPullers.java
+ */
+message SupportedRadioAccessFamily {
+ // A bitmask of supported radio technologies.
+ // See android.telephony.TelephonyManager.NetworkTypeBitMask.
+ optional int64 network_type_bitmask = 1;
+}
+
+/**
* Logs gnss stats from location service provider
*
* Pulled from:
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 0115ba2..8b6a5a1 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -32,7 +32,7 @@
#include "../statscompanion_util.h"
#include "StatsCallbackPuller.h"
#include "TrainInfoPuller.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
using std::shared_ptr;
using std::vector;
@@ -47,7 +47,7 @@
StatsPullerManager::StatsPullerManager()
: kAllPullAtomInfo({
// TrainInfo.
- {{.atomTag = android::util::TRAIN_INFO}, new TrainInfoPuller()},
+ {{.atomTag = util::TRAIN_INFO}, new TrainInfoPuller()},
}),
mNextPullTimeNs(NO_ALARM_UPDATE) {
}
diff --git a/cmds/statsd/src/external/TrainInfoPuller.cpp b/cmds/statsd/src/external/TrainInfoPuller.cpp
index a7d8d4e..3837f4a 100644
--- a/cmds/statsd/src/external/TrainInfoPuller.cpp
+++ b/cmds/statsd/src/external/TrainInfoPuller.cpp
@@ -22,7 +22,7 @@
#include "TrainInfoPuller.h"
#include "logd/LogEvent.h"
#include "stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
#include "storage/StorageManager.h"
using std::make_shared;
@@ -33,7 +33,7 @@
namespace statsd {
TrainInfoPuller::TrainInfoPuller() :
- StatsPuller(android::util::TRAIN_INFO) {
+ StatsPuller(util::TRAIN_INFO) {
}
bool TrainInfoPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 3054b6d..2bd13d7 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -20,7 +20,7 @@
#include <android/util/ProtoOutputStream.h>
#include "../stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
#include "storage/StorageManager.h"
namespace android {
@@ -113,9 +113,9 @@
const int FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL_TIME = 2;
const std::map<int, std::pair<size_t, size_t>> StatsdStats::kAtomDimensionKeySizeLimitMap = {
- {android::util::BINDER_CALLS, {6000, 10000}},
- {android::util::LOOPER_STATS, {1500, 2500}},
- {android::util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
+ {util::BINDER_CALLS, {6000, 10000}},
+ {util::LOOPER_STATS, {1500, 2500}},
+ {util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
};
StatsdStats::StatsdStats() {
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 974e203c..258f84d 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -18,7 +18,7 @@
#include "logd/LogEvent.h"
#include "stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
#include <android/binder_ibinder.h>
#include <android-base/stringprintf.h>
@@ -100,7 +100,7 @@
const std::map<int32_t, float>& float_map) {
mLogdTimestampNs = wallClockTimestampNs;
mElapsedTimestampNs = elapsedTimestampNs;
- mTagId = android::util::KEY_VALUE_PAIRS_ATOM;
+ mTagId = util::KEY_VALUE_PAIRS_ATOM;
mLogUid = uid;
int pos[] = {1, 1, 1};
@@ -153,7 +153,7 @@
const std::vector<uint8_t>& experimentIds, int32_t userId) {
mLogdTimestampNs = getWallClockNs();
mElapsedTimestampNs = getElapsedRealtimeNs();
- mTagId = android::util::BINARY_PUSH_STATE_CHANGED;
+ mTagId = util::BINARY_PUSH_STATE_CHANGED;
mLogUid = AIBinder_getCallingUid();
mLogPid = AIBinder_getCallingPid();
@@ -172,7 +172,7 @@
const InstallTrainInfo& trainInfo) {
mLogdTimestampNs = wallClockTimestampNs;
mElapsedTimestampNs = elapsedTimestampNs;
- mTagId = android::util::TRAIN_INFO;
+ mTagId = util::TRAIN_INFO;
mValues.push_back(
FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 3940aa8..b68eeb8 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -328,4 +328,3 @@
} // namespace statsd
} // namespace os
} // namespace android
-
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 536700f..6f54ea7 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -31,7 +31,7 @@
#include "state/StateManager.h"
#include "stats_log_util.h"
#include "stats_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_INT32;
@@ -291,7 +291,7 @@
}
bool MetricsManager::eventSanityCheck(const LogEvent& event) {
- if (event.GetTagId() == android::util::APP_BREADCRUMB_REPORTED) {
+ if (event.GetTagId() == util::APP_BREADCRUMB_REPORTED) {
// Check that app breadcrumb reported fields are valid.
status_t err = NO_ERROR;
@@ -318,7 +318,7 @@
VLOG("APP_BREADCRUMB_REPORTED does not have valid state %ld", appHookState);
return false;
}
- } else if (event.GetTagId() == android::util::DAVEY_OCCURRED) {
+ } else if (event.GetTagId() == util::DAVEY_OCCURRED) {
// Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
// Check that the davey duration is reasonable. Max length check is for privacy.
status_t err = NO_ERROR;
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 4e3c506..02fe7b1 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -139,7 +139,7 @@
// record is deleted.
void appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set,
bool includeVersionStrings, bool includeInstaller,
- util::ProtoOutputStream* proto);
+ ProtoOutputStream* proto);
// Forces the output to be cleared. We still generate a snapshot based on the current state.
// This results in extra data uploaded but helps us reconstruct the uid mapping on the server
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 4b78e30..7febb35 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -137,7 +137,9 @@
simplePredicate, trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
- LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+ // This event is not accessed in this test besides dimensions which is why this is okay.
+ // This is technically an invalid LogEvent because we do not call parseBuffer.
+ LogEvent event(/*uid=*/0, /*pid=*/0);
vector<MatchingState> matcherState;
matcherState.push_back(MatchingState::kNotMatched);
@@ -222,7 +224,9 @@
trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
- LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+ // This event is not accessed in this test besides dimensions which is why this is okay.
+ // This is technically an invalid LogEvent because we do not call parseBuffer.
+ LogEvent event(/*uid=*/0, /*pid=*/0);
// one matched start
vector<MatchingState> matcherState;
@@ -296,8 +300,8 @@
std::vector<int> uids = {111, 222, 333};
- LogEvent event(/*uid=*/-1, /*pid=*/-1);
- makeWakeLockEvent(&event, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1);
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1);
// one matched start
vector<MatchingState> matcherState;
@@ -308,7 +312,7 @@
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
+ conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
changedCache);
if (position == Position::FIRST || position == Position::LAST) {
@@ -333,7 +337,7 @@
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by this uid
- LogEvent event2(/*uid=*/-1, /*pid=*/-1);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/1);
matcherState.clear();
matcherState.push_back(MatchingState::kMatched);
@@ -353,7 +357,7 @@
// wake lock 1 release
- LogEvent event3(/*uid=*/-1, /*pid=*/-1);
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/0);
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
@@ -372,7 +376,7 @@
EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
- LogEvent event4(/*uid=*/-1, /*pid=*/-1);
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/0);
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
@@ -399,246 +403,235 @@
}
-//TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
-// std::vector<sp<ConditionTracker>> allConditions;
-//
-// SimplePredicate simplePredicate = getWakeLockHeldCondition(
-// true /*nesting*/, true /*default to false*/, false /*slice output by uid*/,
-// Position::ANY /* position */);
-// string conditionName = "WL_HELD";
-//
-// unordered_map<int64_t, int> trackerNameIndexMap;
-// trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
-// trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
-// trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
-//
-// SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
-// 0 /*condition tracker index*/, simplePredicate,
-// trackerNameIndexMap);
-//
-// EXPECT_FALSE(conditionTracker.isSliced());
-//
-// std::vector<int> uid_list1 = {111, 1111, 11111};
-// string uid1_wl1 = "wl1_1";
-// std::vector<int> uid_list2 = {222, 2222, 22222};
-// string uid2_wl1 = "wl2_1";
-//
-// LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event, uid_list1, uid1_wl1, 1);
-//
-// // one matched start for uid1
-// vector<MatchingState> matcherState;
-// matcherState.push_back(MatchingState::kMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// vector<sp<ConditionTracker>> allPredicates;
-// vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-// vector<bool> changedCache(1, false);
-//
-// conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-// changedCache);
-//
-// EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-// EXPECT_TRUE(changedCache[0]);
-//
-// // Now test query
-// ConditionKey queryKey;
-// conditionCache[0] = ConditionState::kNotEvaluated;
-//
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// true,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-//
-// // another wake lock acquired by this uid
-// LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event2, uid_list2, uid2_wl1, 1);
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
-// changedCache);
-// EXPECT_FALSE(changedCache[0]);
-//
-// // uid1 wake lock 1 release
-// LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event3, uid_list1, uid1_wl1, 0); // now release it.
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kMatched);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
-// changedCache);
-// // nothing changes, because uid2 is still holding wl.
-// EXPECT_FALSE(changedCache[0]);
-//
-// LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event4, uid_list2, uid2_wl1, 0); // now release it.
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kMatched);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
-// changedCache);
-// EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
-// EXPECT_TRUE(changedCache[0]);
-//
-// // query again
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// true,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-//}
-//
-//TEST(SimpleConditionTrackerTest, TestStopAll) {
-// std::vector<sp<ConditionTracker>> allConditions;
-// for (Position position :
-// { Position::FIRST, Position::LAST }) {
-// SimplePredicate simplePredicate = getWakeLockHeldCondition(
-// true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
-// position);
-// string conditionName = "WL_HELD_BY_UID3";
-//
-// unordered_map<int64_t, int> trackerNameIndexMap;
-// trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
-// trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
-// trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
-//
-// SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
-// 0 /*condition tracker index*/, simplePredicate,
-// trackerNameIndexMap);
-//
-// std::vector<int> uid_list1 = {111, 1111, 11111};
-// std::vector<int> uid_list2 = {222, 2222, 22222};
-//
-// LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event, uid_list1, "wl1", 1);
-//
-// // one matched start
-// vector<MatchingState> matcherState;
-// matcherState.push_back(MatchingState::kMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// vector<sp<ConditionTracker>> allPredicates;
-// vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-// vector<bool> changedCache(1, false);
-//
-// conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-// changedCache);
-// if (position == Position::FIRST ||
-// position == Position::LAST) {
-// EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-// } else {
-// EXPECT_EQ(uid_list1.size(), conditionTracker.mSlicedConditionState.size());
-// }
-// EXPECT_TRUE(changedCache[0]);
-// {
-// if (position == Position::FIRST ||
-// position == Position::LAST) {
-// EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-// } else {
-// EXPECT_EQ(uid_list1.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-// }
-// }
-//
-// // Now test query
-// const auto queryKey = getWakeLockQueryKey(position, uid_list1, conditionName);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-//
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// false,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-//
-// // another wake lock acquired by uid2
-// LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event2, uid_list2, "wl2", 1);
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
-// changedCache);
-// if (position == Position::FIRST ||
-// position == Position::LAST) {
-// EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
-// } else {
-// EXPECT_EQ(uid_list1.size() + uid_list2.size(),
-// conditionTracker.mSlicedConditionState.size());
-// }
-// EXPECT_TRUE(changedCache[0]);
-// {
-// if (position == Position::FIRST ||
-// position == Position::LAST) {
-// EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-// } else {
-// EXPECT_EQ(uid_list2.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-// }
-// }
-//
-//
-// // TEST QUERY
-// const auto queryKey2 = getWakeLockQueryKey(position, uid_list2, conditionName);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// false,
-// conditionCache);
-//
-// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-//
-//
-// // stop all event
-// LogEvent event3(2 /*tagId*/, 0 /*timestamp*/);
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kMatched);
-//
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
-// changedCache);
-// EXPECT_TRUE(changedCache[0]);
-// EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
-// {
-// if (position == Position::FIRST || position == Position::LAST) {
-// EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-// } else {
-// EXPECT_EQ(uid_list1.size() + uid_list2.size(),
-// conditionTracker.getChangedToFalseDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-// }
-// }
-//
-// // TEST QUERY
-// const auto queryKey3 = getWakeLockQueryKey(position, uid_list1, conditionName);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// false,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-//
-// // TEST QUERY
-// const auto queryKey4 = getWakeLockQueryKey(position, uid_list2, conditionName);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// false,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-// }
-//}
+TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
+ std::vector<sp<ConditionTracker>> allConditions;
+
+ SimplePredicate simplePredicate =
+ getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
+ false /*slice output by uid*/, Position::ANY /* position */);
+ string conditionName = "WL_HELD";
+
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+ trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
+
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ 0 /*condition tracker index*/, simplePredicate,
+ trackerNameIndexMap);
+
+ EXPECT_FALSE(conditionTracker.isSliced());
+
+ std::vector<int> uids1 = {111, 1111, 11111};
+ string uid1_wl1 = "wl1_1";
+ std::vector<int> uids2 = {222, 2222, 22222};
+ string uid2_wl1 = "wl2_1";
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1, /*acquire=*/1);
+
+ // one matched start for uid1
+ vector<MatchingState> matcherState;
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allPredicates;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+ vector<bool> changedCache(1, false);
+
+ conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
+ changedCache);
+
+ EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // Now test query
+ ConditionKey queryKey;
+ conditionCache[0] = ConditionState::kNotEvaluated;
+
+ conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+ // another wake lock acquired by this uid
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1, /*acquire=*/1);
+
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_FALSE(changedCache[0]);
+
+ // uid1 wake lock 1 release
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1,
+ /*release=*/0); // now release it.
+
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
+ changedCache);
+ // nothing changes, because uid2 is still holding wl.
+ EXPECT_FALSE(changedCache[0]);
+
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1,
+ /*acquire=*/0); // now release it.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // query again
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+}
+
+TEST(SimpleConditionTrackerTest, TestStopAll) {
+ std::vector<sp<ConditionTracker>> allConditions;
+ for (Position position : {Position::FIRST, Position::LAST}) {
+ SimplePredicate simplePredicate =
+ getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
+ true /*output slice by uid*/, position);
+ string conditionName = "WL_HELD_BY_UID3";
+
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+ trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
+
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ 0 /*condition tracker index*/, simplePredicate,
+ trackerNameIndexMap);
+
+ std::vector<int> uids1 = {111, 1111, 11111};
+ std::vector<int> uids2 = {222, 2222, 22222};
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, "wl1", /*acquire=*/1);
+
+ // one matched start
+ vector<MatchingState> matcherState;
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allPredicates;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+ vector<bool> changedCache(1, false);
+
+ conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
+ changedCache);
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ } else {
+ EXPECT_EQ(uids1.size(), conditionTracker.mSlicedConditionState.size());
+ }
+ EXPECT_TRUE(changedCache[0]);
+ {
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(uids1.size(),
+ conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ }
+ }
+
+ // Now test query
+ const auto queryKey = getWakeLockQueryKey(position, uids1, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+ // another wake lock acquired by uid2
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
+
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
+ changedCache);
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
+ } else {
+ EXPECT_EQ(uids1.size() + uids2.size(), conditionTracker.mSlicedConditionState.size());
+ }
+ EXPECT_TRUE(changedCache[0]);
+ {
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(uids2.size(),
+ conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ }
+ }
+
+ // TEST QUERY
+ const auto queryKey2 = getWakeLockQueryKey(position, uids2, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+ // stop all event
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
+
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_TRUE(changedCache[0]);
+ EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ {
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(uids1.size() + uids2.size(),
+ conditionTracker.getChangedToFalseDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+ }
+ }
+
+ // TEST QUERY
+ const auto queryKey3 = getWakeLockQueryKey(position, uids1, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+
+ // TEST QUERY
+ const auto queryKey4 = getWakeLockQueryKey(position, uids2, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+ }
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
index 1eaaf08..e0eebef 100644
--- a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
@@ -53,185 +53,192 @@
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
-// const int num_buckets = 1;
-// const int threshold = 3;
-// auto config = CreateStatsdConfig(num_buckets, threshold);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-// std::vector<AttributionNodeInternal> attributions2 = {
-// CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
-// std::vector<AttributionNodeInternal> attributions3 = {
-// CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions4 = {
-// CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions5 = {
-// CreateAttribution(222, "GMSCoreModule1") };
-//
-// FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)111));
-// HashableDimensionKey whatKey1({fieldValue1});
-// MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-//
-// FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)222));
-// HashableDimensionKey whatKey2({fieldValue2});
-// MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-//
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 3);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions3, "wl1", bucketStartTimeNs + 4);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 4);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// // Fired alarm and refractory period end timestamp updated.
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 5);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 100);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + bucketSizeNs + 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 3);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 4);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//}
-//
-//TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
-// const int num_buckets = 3;
-// const int threshold = 3;
-// auto config = CreateStatsdConfig(num_buckets, threshold);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-// std::vector<AttributionNodeInternal> attributions2 = {
-// CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
-// std::vector<AttributionNodeInternal> attributions3 = {
-// CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions4 = {
-// CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions5 = {
-// CreateAttribution(222, "GMSCoreModule1") };
-//
-// FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)111));
-// HashableDimensionKey whatKey1({fieldValue1});
-// MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-//
-// FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)222));
-// HashableDimensionKey whatKey2({fieldValue2});
-// MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-//
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// // Fired alarm and refractory period end timestamp updated.
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 4);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//}
+TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
+ const int num_buckets = 1;
+ const int threshold = 3;
+ auto config = CreateStatsdConfig(num_buckets, threshold);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ std::vector<int> attributionUids1 = {111};
+ std::vector<string> attributionTags1 = {"App1"};
+ std::vector<int> attributionUids2 = {111, 222};
+ std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
+ std::vector<int> attributionUids3 = {111, 333};
+ std::vector<string> attributionTags3 = {"App1", "App3"};
+ std::vector<int> attributionUids4 = {222, 333};
+ std::vector<string> attributionTags4 = {"GMSCoreModule1", "App3"};
+ std::vector<int> attributionUids5 = {222};
+ std::vector<string> attributionTags5 = {"GMSCoreModule1"};
+
+ FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)111));
+ HashableDimensionKey whatKey1({fieldValue1});
+ MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+ FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)222));
+ HashableDimensionKey whatKey2({fieldValue2});
+ MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids4, attributionTags4,
+ "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids5, attributionTags5,
+ "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids3, attributionTags3,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids5, attributionTags5,
+ "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ // Fired alarm and refractory period end timestamp updated.
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 5, attributionUids1, attributionTags1,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 100, attributionUids1, attributionTags1,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids4,
+ attributionTags4, "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids5,
+ attributionTags5, "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 3, attributionUids5,
+ attributionTags5, "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 4, attributionUids5,
+ attributionTags5, "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+}
+
+TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
+ const int num_buckets = 3;
+ const int threshold = 3;
+ auto config = CreateStatsdConfig(num_buckets, threshold);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ std::vector<int> attributionUids1 = {111};
+ std::vector<string> attributionTags1 = {"App1"};
+ std::vector<int> attributionUids2 = {111, 222};
+ std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
+
+ FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)111));
+ HashableDimensionKey whatKey1({fieldValue1});
+ MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Fired alarm and refractory period end timestamp updated.
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids1, attributionTags1,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 2, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
index 03a209a..fe45b55 100644
--- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
@@ -69,414 +69,432 @@
return config;
}
-} // namespace
+std::vector<int> attributionUids1 = {111, 222};
+std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1"};
-std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
- CreateAttribution(222, "GMSCoreModule1")};
+std::vector<int> attributionUids2 = {111, 222};
+std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1"};
-std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"),
- CreateAttribution(222, "GMSCoreModule1")};
+std::vector<int> attributionUids3 = {222};
+std::vector<string> attributionTags3 = {"GMSCoreModule1"};
-std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1")};
-
-MetricDimensionKey dimensionKey(
- HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
- (int32_t)0x02010101), Value((int32_t)111))}),
- DEFAULT_DIMENSION_KEY);
+MetricDimensionKey dimensionKey1(
+ HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
+ (int32_t)0x02010101),
+ Value((int32_t)111))}),
+ DEFAULT_DIMENSION_KEY);
MetricDimensionKey dimensionKey2(
HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
(int32_t)0x02010101), Value((int32_t)222))}),
DEFAULT_DIMENSION_KEY);
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
-// const int num_buckets = 1;
-// const uint64_t threshold_ns = NS_PER_SEC;
-// auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// auto screen_on_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1);
-// auto screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 10);
-// processor->OnLogEvent(screen_on_event.get());
-// processor->OnLogEvent(screen_off_event.get());
-//
-// // Acquire wakelock wl1.
-// auto acquire_event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 11);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
-// auto release_event = CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 101);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock wl1 within bucket #0.
-// acquire_event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 110);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock wl1. One anomaly detected.
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + NS_PER_SEC + 109);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock wl1.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + NS_PER_SEC + 112);
-// processor->OnLogEvent(acquire_event.get());
-// // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
-// // end of the refractory period.
-// const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
-// (uint32_t)alarmFiredTimestampSec0);
-//
-// // Anomaly alarm fired.
-// auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-// static_cast<uint32_t>(alarmFiredTimestampSec0));
-// EXPECT_EQ(1u, alarmSet.size());
-// processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock wl1.
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// // Within refractory period. No more anomaly detected.
-// EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock wl1.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11);
-// processor->OnLogEvent(acquire_event.get());
-// const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
-// (uint64_t)alarmFiredTimestampSec1);
-//
-// // Release wakelock wl1.
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-// static_cast<uint32_t>(alarmFiredTimestampSec1));
-// EXPECT_EQ(0u, alarmSet.size());
-//
-// // Acquire wakelock wl1 near the end of bucket #0.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 2);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// // Release the event at early bucket #1.
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// // Anomaly detected when stopping the alarm. The refractory period does not change.
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Condition changes to false.
-// screen_on_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2 * bucketSizeNs + 20);
-// processor->OnLogEvent(screen_on_event.get());
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 30);
-// processor->OnLogEvent(acquire_event.get());
-// // The condition is false. Do not start the alarm.
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Condition turns true.
-// screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC);
-// processor->OnLogEvent(screen_off_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// // Condition turns to false.
-// screen_on_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1);
-// processor->OnLogEvent(screen_on_event.get());
-// // Condition turns to false. Cancelled the alarm.
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// // Detected one anomaly.
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Condition turns to true again.
-// screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2);
-// processor->OnLogEvent(screen_off_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//}
-//
-//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
-// const int num_buckets = 3;
-// const uint64_t threshold_ns = NS_PER_SEC;
-// auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// auto screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
-// processor->OnLogEvent(screen_off_event.get());
-//
-// // Acquire wakelock "wc1" in bucket #0.
-// auto acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock "wc1" in bucket #0.
-// auto release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock "wc1" in bucket #1.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 100);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock "wc2" in bucket #2.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// // Release wakelock "wc2" in bucket #2.
-// release_event = CreateReleaseWakelockEvent(
-// attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// // Acquire wakelock "wc1" in bucket #2.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock "wc1" in bucket #2.
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec +
-// (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4);
-// processor->OnLogEvent(acquire_event.get());
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs + 2);
-// processor->OnLogEvent(release_event.get());
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs + 6);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-// // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
-// EXPECT_EQ(refractory_period_sec +
-// (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//}
-//
-//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
-// const int num_buckets = 2;
-// const uint64_t threshold_ns = 3 * NS_PER_SEC;
-// auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
-// int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-//
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
-// config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// auto screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
-// processor->OnLogEvent(screen_off_event.get());
-//
-// // Acquire wakelock "wc1" in bucket #0.
-// auto acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 100);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire the wakelock "wc1" again.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1);
-// processor->OnLogEvent(acquire_event.get());
-// // The alarm does not change.
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Anomaly alarm fired late.
-// const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
-// auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-// static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
-// EXPECT_EQ(1u, alarmSet.size());
-// processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs - 100);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// auto release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// // Within the refractory period. No anomaly.
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // A new wakelock, but still within refractory period.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC);
-// // Still in the refractory period. No anomaly.
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//}
+} // namespace
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
+ const int num_buckets = 1;
+ const uint64_t threshold_ns = NS_PER_SEC;
+ auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+ int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ auto screen_on_event = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ auto screen_off_event = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 10, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_on_event.get());
+ processor->OnLogEvent(screen_off_event.get());
+
+ // Acquire wakelock wl1.
+ auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 11, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
+ auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 101, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock wl1 within bucket #0.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 110, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock wl1. One anomaly detected.
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 109,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock wl1.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 112,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
+ // end of the refractory period.
+ const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
+ (uint32_t)alarmFiredTimestampSec0);
+
+ // Anomaly alarm fired.
+ auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+ static_cast<uint32_t>(alarmFiredTimestampSec0));
+ EXPECT_EQ(1u, alarmSet.size());
+ processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock wl1.
+ release_event =
+ CreateReleaseWakelockEvent(alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ // Within refractory period. No more anomaly detected.
+ EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock wl1.
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
+ (uint64_t)alarmFiredTimestampSec1);
+
+ // Release wakelock wl1.
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec +
+ (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+ static_cast<uint32_t>(alarmFiredTimestampSec1));
+ EXPECT_EQ(0u, alarmSet.size());
+
+ // Acquire wakelock wl1 near the end of bucket #0.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ // Release the event at early bucket #1.
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ // Anomaly detected when stopping the alarm. The refractory period does not change.
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Condition changes to false.
+ screen_on_event =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 20,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screen_on_event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 30,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ // The condition is false. Do not start the alarm.
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Condition turns true.
+ screen_off_event =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_off_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ // Condition turns to false.
+ screen_on_event =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screen_on_event.get());
+ // Condition turns to false. Cancelled the alarm.
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ // Detected one anomaly.
+ EXPECT_EQ(refractory_period_sec +
+ (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Condition turns to true again.
+ screen_off_event =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_off_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(refractory_period_sec +
+ (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+}
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
+ const int num_buckets = 3;
+ const uint64_t threshold_ns = NS_PER_SEC;
+ auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+ int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ auto screen_off_event = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_off_event.get());
+
+ // Acquire wakelock "wc1" in bucket #0.
+ auto acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock "wc1" in bucket #0.
+ auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock "wc1" in bucket #1.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock "wc2" in bucket #2.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ attributionUids3, attributionTags3, "wl2");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ // Release wakelock "wc2" in bucket #2.
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
+ attributionUids3, attributionTags3, "wl2");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+ EXPECT_EQ(refractory_period_sec +
+ (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ // Acquire wakelock "wc1" in bucket #2.
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock "wc1" in bucket #2.
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec +
+ (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) /
+ NS_PER_SEC +
+ 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4,
+ attributionUids3, attributionTags3, "wl2");
+ processor->OnLogEvent(acquire_event.get());
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2,
+ attributionUids3, attributionTags3, "wl2");
+ processor->OnLogEvent(release_event.get());
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+ // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
+ EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC +
+ 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+}
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
+ const int num_buckets = 2;
+ const uint64_t threshold_ns = 3 * NS_PER_SEC;
+ auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
+ int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
+ config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ auto screen_off_event = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_off_event.get());
+
+ // Acquire wakelock "wc1" in bucket #0.
+ auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire the wakelock "wc1" again.
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ // The alarm does not change.
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Anomaly alarm fired late.
+ const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
+ auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+ static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
+ EXPECT_EQ(1u, alarmSet.size());
+ processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ // Within the refractory period. No anomaly.
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // A new wakelock, but still within refractory period.
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1");
+ // Still in the refractory period. No anomaly.
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 6051174..9e743f7 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -53,367 +53,318 @@
return config;
}
+// GMS core node is in the middle.
+std::vector<int> attributionUids1 = {111, 222, 333};
+std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "App3"};
+
+// GMS core node is the last one.
+std::vector<int> attributionUids2 = {111, 333, 222};
+std::vector<string> attributionTags2 = {"App1", "App3", "GMSCoreModule1"};
+
+// GMS core node is the first one.
+std::vector<int> attributionUids3 = {222, 333};
+std::vector<string> attributionTags3 = {"GMSCoreModule1", "App3"};
+
+// Single GMS core node.
+std::vector<int> attributionUids4 = {222};
+std::vector<string> attributionTags4 = {"GMSCoreModule1"};
+
+// GMS core has another uid.
+std::vector<int> attributionUids5 = {111, 444, 333};
+std::vector<string> attributionTags5 = {"App1", "GMSCoreModule2", "App3"};
+
+// Multiple GMS core nodes.
+std::vector<int> attributionUids6 = {444, 222};
+std::vector<string> attributionTags6 = {"GMSCoreModule2", "GMSCoreModule1"};
+
+// No GMS core nodes
+std::vector<int> attributionUids7 = {111, 333};
+std::vector<string> attributionTags7 = {"App1", "App3"};
+
+std::vector<int> attributionUids8 = {111};
+std::vector<string> attributionTags8 = {"App1"};
+
+// GMS core node with isolated uid.
+const int isolatedUid = 666;
+std::vector<int> attributionUids9 = {isolatedUid};
+std::vector<string> attributionTags9 = {"GMSCoreModule3"};
+
+std::vector<int> attributionUids10 = {isolatedUid};
+std::vector<string> attributionTags10 = {"GMSCoreModule1"};
+
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
-// auto config = CreateStatsdConfig(Position::FIRST);
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// // Here it assumes that GMS core has two uids.
-// processor->getUidMap()->updateMap(
-// 1, {222, 444, 111, 333}, {1, 1, 2, 2},
-// {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
-// {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
-// String16("APP3")},
-// {String16(""), String16(""), String16(""), String16("")});
-//
-// // GMS core node is in the middle.
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
-// CreateAttribution(222, "GMSCoreModule1"),
-// CreateAttribution(333, "App3")};
-//
-// // GMS core node is the last one.
-// std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
-// CreateAttribution(333, "App3"),
-// CreateAttribution(222, "GMSCoreModule1")};
-//
-// // GMS core node is the first one.
-// std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
-// CreateAttribution(333, "App3")};
-//
-// // Single GMS core node.
-// std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
-//
-// // GMS core has another uid.
-// std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
-// CreateAttribution(444, "GMSCoreModule2"),
-// CreateAttribution(333, "App3")};
-//
-// // Multiple GMS core nodes.
-// std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
-// CreateAttribution(222, "GMSCoreModule1")};
-//
-// // No GMS core nodes.
-// std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
-// CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
-//
-// // GMS core node with isolated uid.
-// const int isolatedUid = 666;
-// std::vector<AttributionNodeInternal> attributions9 = {
-// CreateAttribution(isolatedUid, "GMSCoreModule3")};
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// // Events 1~4 are in the 1st bucket.
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 200));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
-//
-// // Events 5~8 are in the 3rd bucket.
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
-// events.push_back(CreateIsolatedUidChangedEvent(
-// isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
-// events.push_back(CreateIsolatedUidChangedEvent(
-// isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(countMetrics.data_size(), 4);
-//
-// auto data = countMetrics.data(0);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 111,
-// "App1");
-// EXPECT_EQ(data.bucket_info_size(), 2);
-// EXPECT_EQ(data.bucket_info(0).count(), 2);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(1).count(), 1);
-// EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-//
-// data = countMetrics.data(1);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222,
-// "GMSCoreModule1");
-// EXPECT_EQ(data.bucket_info_size(), 2);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(1).count(), 1);
-// EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-//
-// data = countMetrics.data(2);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222,
-// "GMSCoreModule3");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
-//
-// data = countMetrics.data(3);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 444,
-// "GMSCoreModule2");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-//}
-//
-//TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
-// auto config = CreateStatsdConfig(Position::ALL);
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// // Here it assumes that GMS core has two uids.
-// processor->getUidMap()->updateMap(
-// 1, {222, 444, 111, 333}, {1, 1, 2, 2},
-// {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
-// {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
-// String16("APP3")},
-// {String16(""), String16(""), String16(""), String16("")});
-//
-// // GMS core node is in the middle.
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
-// CreateAttribution(222, "GMSCoreModule1"),
-// CreateAttribution(333, "App3")};
-//
-// // GMS core node is the last one.
-// std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
-// CreateAttribution(333, "App3"),
-// CreateAttribution(222, "GMSCoreModule1")};
-//
-// // GMS core node is the first one.
-// std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
-// CreateAttribution(333, "App3")};
-//
-// // Single GMS core node.
-// std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
-//
-// // GMS core has another uid.
-// std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
-// CreateAttribution(444, "GMSCoreModule2"),
-// CreateAttribution(333, "App3")};
-//
-// // Multiple GMS core nodes.
-// std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
-// CreateAttribution(222, "GMSCoreModule1")};
-//
-// // No GMS core nodes.
-// std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
-// CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
-//
-// // GMS core node with isolated uid.
-// const int isolatedUid = 666;
-// std::vector<AttributionNodeInternal> attributions9 = {
-// CreateAttribution(isolatedUid, "GMSCoreModule1")};
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// // Events 1~4 are in the 1st bucket.
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 200));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
-//
-// // Events 5~8 are in the 3rd bucket.
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
-// events.push_back(CreateIsolatedUidChangedEvent(
-// isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
-// events.push_back(CreateIsolatedUidChangedEvent(
-// isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(countMetrics.data_size(), 6);
-//
-// auto data = countMetrics.data(0);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(1).count());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs,
-// data.bucket_info(1).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-//
-// data = countMetrics.data(2);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(bucketStartTimeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(bucketStartTimeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(5);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
+ auto config = CreateStatsdConfig(Position::FIRST);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ // Here it assumes that GMS core has two uids.
+ processor->getUidMap()->updateMap(
+ 1, {222, 444, 111, 333}, {1, 1, 2, 2},
+ {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
+ {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+ String16("APP3")},
+ {String16(""), String16(""), String16(""), String16("")});
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ // Events 1~4 are in the 1st bucket.
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2,
+ attributionTags2, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
+ attributionUids3, attributionTags3, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4,
+ attributionTags4, "wl1"));
+
+ // Events 5~8 are in the 3rd bucket.
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ attributionUids5, attributionTags5, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+ attributionUids6, attributionTags6, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2,
+ attributionUids7, attributionTags7, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs,
+ attributionUids8, attributionTags8, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1,
+ attributionUids9, attributionTags9, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100,
+ attributionUids9, attributionTags9, "wl2"));
+ events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222,
+ isolatedUid, true /*is_create*/));
+ events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222,
+ isolatedUid, false /*is_create*/));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(countMetrics.data_size(), 4);
+
+ auto data = countMetrics.data(0);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).count(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).count(), 1);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+
+ data = countMetrics.data(1);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).count(), 1);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = countMetrics.data(2);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 3 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
+
+ data = countMetrics.data(3);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 444,
+ "GMSCoreModule2");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+}
+
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
+ auto config = CreateStatsdConfig(Position::ALL);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ // Here it assumes that GMS core has two uids.
+ processor->getUidMap()->updateMap(
+ 1, {222, 444, 111, 333}, {1, 1, 2, 2},
+ {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
+ {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+ String16("APP3")},
+ {String16(""), String16(""), String16(""), String16("")});
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ // Events 1~4 are in the 1st bucket.
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2,
+ attributionTags2, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
+ attributionUids3, attributionTags3, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4,
+ attributionTags4, "wl1"));
+
+ // Events 5~8 are in the 3rd bucket.
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ attributionUids5, attributionTags5, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+ attributionUids6, attributionTags6, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2,
+ attributionUids7, attributionTags7, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs,
+ attributionUids8, attributionTags8, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1,
+ attributionUids10, attributionTags10, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100,
+ attributionUids10, attributionTags10, "wl2"));
+ events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222,
+ isolatedUid, true /*is_create*/));
+ events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222,
+ isolatedUid, false /*is_create*/));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(countMetrics.data_size(), 6);
+
+ auto data = countMetrics.data(0);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+
+ data = countMetrics.data(2);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 444,
+ "GMSCoreModule2");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
+ android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(5);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 444,
+ "GMSCoreModule2");
+ ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
+ android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
index f8edee5..102bb1e 100644
--- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
@@ -56,54 +56,54 @@
} // namespace
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(ConfigTtlE2eTest, TestCountMetric) {
-// const int num_buckets = 1;
-// const int threshold = 3;
-// auto config = CreateStatsdConfig(num_buckets, threshold);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-//
-// FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)111));
-// HashableDimensionKey whatKey1({fieldValue1});
-// MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-//
-// FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)222));
-// HashableDimensionKey whatKey2({fieldValue2});
-// MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-//
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-// processor->OnLogEvent(event.get());
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl2", bucketStartTimeNs + bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-//
-// event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 25 * bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-//
-// EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC),
-// processor->mMetricsManagers.begin()->second->getTtlEndNs());
-//
-// // Clear the data stored on disk as a result of the ttl.
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true,
-// ADB_DUMP, FAST, &buffer);
-//}
+TEST(ConfigTtlE2eTest, TestCountMetric) {
+ const int num_buckets = 1;
+ const int threshold = 3;
+ auto config = CreateStatsdConfig(num_buckets, threshold);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ std::vector<int> attributionUids1 = {111};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)111));
+ HashableDimensionKey whatKey1({fieldValue1});
+ MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+ FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)222));
+ HashableDimensionKey whatKey2({fieldValue2});
+ MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids1,
+ attributionTags1, "wl2");
+ processor->OnLogEvent(event.get());
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 25 * bucketSizeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+
+ EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC),
+ processor->mMetricsManagers.begin()->second->getTtlEndNs());
+
+ // Clear the data stored on disk as a result of the ttl.
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true,
+ ADB_DUMP, FAST, &buffer);
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
index a1f74a6..2cd7854 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -27,773 +27,775 @@
#ifdef __ANDROID__
-// TODO(b/149590301): Update these tests to use new socket schema.
-///**
-// * Test a count metric that has one slice_by_state with no primary fields.
-// *
-// * Once the CountMetricProducer is initialized, it has one atom id in
-// * mSlicedStateAtoms and no entries in mStateGroupMap.
-//
-// * One StateTracker tracks the state atom, and it has one listener which is the
-// * CountMetricProducer that was initialized.
-// */
-//TEST(CountMetricE2eTest, TestSlicedState) {
-// // Initialize config.
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto syncStartMatcher = CreateSyncStartAtomMatcher();
-// *config.add_atom_matcher() = syncStartMatcher;
-//
-// auto state = CreateScreenState();
-// *config.add_state() = state;
-//
-// // Create count metric that slices by screen state.
-// int64_t metricId = 123456;
-// auto countMetric = config.add_count_metric();
-// countMetric->set_id(metricId);
-// countMetric->set_what(syncStartMatcher.id());
-// countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-// countMetric->add_slice_by_state(state.id());
-//
-// // Initialize StatsLogProcessor.
-// const uint64_t bucketStartTimeNs = 10000000000; // 0:10
-// const uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-// // Check that CountMetricProducer was initialized correctly.
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
-//
-// // Check that StateTrackers were initialized correctly.
-// EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-//
-// /*
-// bucket #1 bucket #2
-// | 1 2 3 4 5 6 7 8 9 10 (minutes)
-// |-----------------------------|-----------------------------|--
-// x x x x x x (syncStartEvents)
-// | | (ScreenIsOnEvent)
-// | | (ScreenIsOffEvent)
-// | (ScreenUnknownEvent)
-// */
-// // Initialize log events - first bucket.
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 50 * NS_PER_SEC)); // 1:00
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 75 * NS_PER_SEC)); // 1:25
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
-//
-// // Initialize log events - second bucket.
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 350 * NS_PER_SEC)); // 6:00
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 400 * NS_PER_SEC)); // 6:50
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 475 * NS_PER_SEC)); // 8:05
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-// bucketStartTimeNs + 500 * NS_PER_SEC)); // 8:30
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50
-//
-// // Send log events to StatsLogProcessor.
-// for (auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// // Check dump report.
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-// FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-// EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// // For each CountMetricData, check StateValue info is correct and buckets
-// // have correct counts.
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(1, data.bucket_info(1).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(1);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(2);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(2, data.bucket_info(1).count());
-//}
-//
-///**
-// * Test a count metric that has one slice_by_state with a mapping and no
-// * primary fields.
-// *
-// * Once the CountMetricProducer is initialized, it has one atom id in
-// * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
-// *
-// * One StateTracker tracks the state atom, and it has one listener which is the
-// * CountMetricProducer that was initialized.
-// */
-//TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
-// // Initialize config.
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto syncStartMatcher = CreateSyncStartAtomMatcher();
-// *config.add_atom_matcher() = syncStartMatcher;
-//
-// auto state = CreateScreenStateWithOnOffMap();
-// *config.add_state() = state;
-//
-// // Create count metric that slices by screen state with on/off map.
-// int64_t metricId = 123456;
-// auto countMetric = config.add_count_metric();
-// countMetric->set_id(metricId);
-// countMetric->set_what(syncStartMatcher.id());
-// countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-// countMetric->add_slice_by_state(state.id());
-//
-// // Initialize StatsLogProcessor.
-// const uint64_t bucketStartTimeNs = 10000000000; // 0:10
-// const uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-// // Check that StateTrackers were initialized correctly.
-// EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-//
-// // Check that CountMetricProducer was initialized correctly.
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
-//
-// StateMap map = state.map();
-// for (auto group : map.group()) {
-// for (auto value : group.value()) {
-// EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
-// group.group_id());
-// }
-// }
-//
-// /*
-// bucket #1 bucket #2
-// | 1 2 3 4 5 6 7 8 9 10 (minutes)
-// |-----------------------------|-----------------------------|--
-// x x x x x x x x x (syncStartEvents)
-// -----------------------------------------------------------SCREEN_OFF events
-// | (ScreenStateUnknownEvent = 0)
-// | | (ScreenStateOffEvent = 1)
-// | (ScreenStateDozeEvent = 3)
-// | (ScreenStateDozeSuspendEvent = 4)
-// -----------------------------------------------------------SCREEN_ON events
-// | | (ScreenStateOnEvent = 2)
-// | (ScreenStateVrEvent = 5)
-// | (ScreenStateOnSuspendEvent = 6)
-// */
-// // Initialize log events - first bucket.
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-// bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_VR,
-// bucketStartTimeNs + 180 * NS_PER_SEC)); // 3:10
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
-// bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55
-//
-// // Initialize log events - second bucket.
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
-// bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40
-// events.push_back(CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND,
-// bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40
-//
-// // Send log events to StatsLogProcessor.
-// for (auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// // Check dump report.
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-// FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-// EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// // For each CountMetricData, check StateValue info is correct and buckets
-// // have correct counts.
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(1);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(4, data.bucket_info(0).count());
-// EXPECT_EQ(2, data.bucket_info(1).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(2);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(1, data.bucket_info(1).count());
-//}
-//
-///**
-// * Test a count metric that has one slice_by_state with a primary field.
-//
-// * Once the CountMetricProducer is initialized, it should have one
-// * MetricStateLink stored. State querying using a non-empty primary key
-// * should also work as intended.
-// */
-//TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
-// // Initialize config.
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto appCrashMatcher =
-// CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
-// *config.add_atom_matcher() = appCrashMatcher;
-//
-// auto state = CreateUidProcessState();
-// *config.add_state() = state;
-//
-// // Create count metric that slices by uid process state.
-// int64_t metricId = 123456;
-// auto countMetric = config.add_count_metric();
-// countMetric->set_id(metricId);
-// countMetric->set_what(appCrashMatcher.id());
-// countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-// countMetric->add_slice_by_state(state.id());
-// MetricStateLink* stateLink = countMetric->add_state_link();
-// stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-// auto fieldsInWhat = stateLink->mutable_fields_in_what();
-// *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
-// auto fieldsInState = stateLink->mutable_fields_in_state();
-// *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-//
-// // Initialize StatsLogProcessor.
-// const uint64_t bucketStartTimeNs = 10000000000; // 0:10
-// const uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-// // Check that StateTrackers were initialized correctly.
-// EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-//
-// // Check that CountMetricProducer was initialized correctly.
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
-// EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
-//
-// /*
-// NOTE: "1" or "2" represents the uid associated with the state/app crash event
-// bucket #1 bucket #2
-// | 1 2 3 4 5 6 7 8 9 10
-// |-----------------------------|-----------------------------|--
-// 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
-// -----------------------------------------------------------PROCESS STATE events
-// 1 2 (ProcessStateTopEvent = 1002)
-// 1 1 (ProcessStateForegroundServiceEvent = 1003)
-// 2 (ProcessStateImportantBackgroundEvent = 1006)
-// 1 1 1 (ProcessStateImportantForegroundEvent = 1005)
-//
-// Based on the diagram above, an AppCrashEvent querying for process state value would return:
-// - StateTracker::kStateUnknown
-// - Important foreground
-// - Top
-// - Important foreground
-// - Foreground service
-// - Top (both the app crash and state still have matching uid = 2)
-//
-// - Foreground service
-// - Foreground service
-// - Important background
-// */
-// // Initialize log events - first bucket.
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(
-// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40
-// events.push_back(
-// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-// bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
-// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-// bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55
-//
-// // Initialize log events - second bucket.
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-// bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-// bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10
-// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-// bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40
-//
-// // Send log events to StatsLogProcessor.
-// for (auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// // Check dump report.
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-// FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// // For each CountMetricData, check StateValue info is correct and buckets
-// // have correct counts.
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(1);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(2);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(2, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(3);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(2, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(4);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(2, data.bucket_info(1).count());
-//}
-//
-//TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
-// // Initialize config.
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto appCrashMatcher =
-// CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
-// *config.add_atom_matcher() = appCrashMatcher;
-//
-// auto state1 = CreateScreenStateWithOnOffMap();
-// *config.add_state() = state1;
-// auto state2 = CreateUidProcessState();
-// *config.add_state() = state2;
-//
-// // Create count metric that slices by screen state with on/off map and
-// // slices by uid process state.
-// int64_t metricId = 123456;
-// auto countMetric = config.add_count_metric();
-// countMetric->set_id(metricId);
-// countMetric->set_what(appCrashMatcher.id());
-// countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-// countMetric->add_slice_by_state(state1.id());
-// countMetric->add_slice_by_state(state2.id());
-// MetricStateLink* stateLink = countMetric->add_state_link();
-// stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-// auto fieldsInWhat = stateLink->mutable_fields_in_what();
-// *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
-// auto fieldsInState = stateLink->mutable_fields_in_state();
-// *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-//
-// // Initialize StatsLogProcessor.
-// const uint64_t bucketStartTimeNs = 10000000000; // 0:10
-// const uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-// // Check that StateTrackers were properly initialized.
-// EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-//
-// // Check that CountMetricProducer was initialized correctly.
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
-// EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
-//
-// StateMap map = state1.map();
-// for (auto group : map.group()) {
-// for (auto value : group.value()) {
-// EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
-// group.group_id());
-// }
-// }
-//
-// /*
-// bucket #1 bucket #2
-// | 1 2 3 4 5 6 7 8 9 10 (minutes)
-// |-----------------------------|-----------------------------|--
-// 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
-// -----------------------------------------------------------SCREEN_OFF events
-// | (ScreenStateUnknownEvent = 0)
-// | | (ScreenStateOffEvent = 1)
-// | (ScreenStateDozeEvent = 3)
-// -----------------------------------------------------------SCREEN_ON events
-// | | (ScreenStateOnEvent = 2)
-// | (ScreenStateOnSuspendEvent = 6)
-// -----------------------------------------------------------PROCESS STATE events
-// 1 2 (ProcessStateTopEvent = 1002)
-// 1 (ProcessStateForegroundServiceEvent = 1003)
-// 2 (ProcessStateImportantBackgroundEvent = 1006)
-// 1 1 1 (ProcessStateImportantForegroundEvent = 1005)
-//
-// Based on the diagram above, Screen State / Process State pairs for each
-// AppCrashEvent are:
-// - StateTracker::kStateUnknown / important foreground
-// - off / important foreground
-// - off / Top
-// - on / important foreground
-// - off / important foreground
-// - off / top
-//
-// - off / important foreground
-// - off / foreground service
-// - on / important background
-//
-// */
-// // Initialize log events - first bucket.
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 5 * NS_PER_SEC)); // 0:15
-// events.push_back(
-// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-// bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40
-// events.push_back(
-// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 160 * NS_PER_SEC)); // 2:50
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
-// bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
-// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-// bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55
-//
-// // Initialize log events - second bucket.
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-// bucketStartTimeNs + 380 * NS_PER_SEC)); // 6:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
-// bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-// bucketStartTimeNs + 420 * NS_PER_SEC)); // 7:10
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10
-// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-// bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40
-//
-// // Send log events to StatsLogProcessor.
-// for (auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// // Check dump report.
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-// FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-// EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// // For each CountMetricData, check StateValue info is correct and buckets
-// // have correct counts.
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(1);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(-1, data.slice_by_state(0).value());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(2);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(2, data.bucket_info(0).count());
-// EXPECT_EQ(1, data.bucket_info(1).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(3);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(4);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(5);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(2, data.bucket_info(0).count());
-//}
+/**
+* Test a count metric that has one slice_by_state with no primary fields.
+*
+* Once the CountMetricProducer is initialized, it has one atom id in
+* mSlicedStateAtoms and no entries in mStateGroupMap.
+
+* One StateTracker tracks the state atom, and it has one listener which is the
+* CountMetricProducer that was initialized.
+*/
+TEST(CountMetricE2eTest, TestSlicedState) {
+ // Initialize config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto syncStartMatcher = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = syncStartMatcher;
+
+ auto state = CreateScreenState();
+ *config.add_state() = state;
+
+ // Create count metric that slices by screen state.
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(syncStartMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ countMetric->add_slice_by_state(state.id());
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that CountMetricProducer was initialized correctly.
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+ /*
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10 (minutes)
+ |-----------------------------|-----------------------------|--
+ x x x x x x (syncStartEvents)
+ | | (ScreenIsOnEvent)
+ | | (ScreenIsOffEvent)
+ | (ScreenUnknownEvent)
+ */
+ // Initialize log events - first bucket.
+ std::vector<int> attributionUids1 = {123};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 50 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 1:00
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 75 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 1:25
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 150 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 2:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 200 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 3:30
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 4:20
+
+ // Initialize log events - second bucket.
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 350 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 6:00
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 6:50
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 450 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 7:40
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 475 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 8:05
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 500 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 8:30
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 520 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 8:50
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
+ data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(2, data.bucket_info(1).count());
+}
+
+/**
+ * Test a count metric that has one slice_by_state with a mapping and no
+ * primary fields.
+ *
+ * Once the CountMetricProducer is initialized, it has one atom id in
+ * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
+ *
+ * One StateTracker tracks the state atom, and it has one listener which is the
+ * CountMetricProducer that was initialized.
+ */
+TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
+ // Initialize config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto syncStartMatcher = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = syncStartMatcher;
+
+ auto state = CreateScreenStateWithOnOffMap();
+ *config.add_state() = state;
+
+ // Create count metric that slices by screen state with on/off map.
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(syncStartMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ countMetric->add_slice_by_state(state.id());
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+ // Check that CountMetricProducer was initialized correctly.
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+
+ StateMap map = state.map();
+ for (auto group : map.group()) {
+ for (auto value : group.value()) {
+ EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
+ group.group_id());
+ }
+ }
+
+ /*
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10 (minutes)
+ |-----------------------------|-----------------------------|--
+ x x x x x x x x x (syncStartEvents)
+ -----------------------------------------------------------SCREEN_OFF events
+ | (ScreenStateUnknownEvent = 0)
+ | | (ScreenStateOffEvent = 1)
+ | (ScreenStateDozeEvent = 3)
+ | (ScreenStateDozeSuspendEvent =
+ 4)
+ -----------------------------------------------------------SCREEN_ON events
+ | | (ScreenStateOnEvent = 2)
+ | (ScreenStateVrEvent = 5)
+ | (ScreenStateOnSuspendEvent = 6)
+ */
+ // Initialize log events - first bucket.
+ std::vector<int> attributionUids1 = {123};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 20 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 0:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 30 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 0:40
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 1:10
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 90 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 120 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 2:10
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 150 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 180 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_VR)); // 3:10
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 3:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 210 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 3:40
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 4:20
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 280 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 4:50
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 285 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 4:55
+
+ // Initialize log events - second bucket.
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 360 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 6:10
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 390 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND)); // 6:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 430 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND)); // 7:20
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 440 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 7:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 540 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 9:10
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 570 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 9:40
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(4, data.bucket_info(0).count());
+ EXPECT_EQ(2, data.bucket_info(1).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+}
+
+/**
+* Test a count metric that has one slice_by_state with a primary field.
+
+* Once the CountMetricProducer is initialized, it should have one
+* MetricStateLink stored. State querying using a non-empty primary key
+* should also work as intended.
+*/
+TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
+ // Initialize config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto appCrashMatcher =
+ CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+ *config.add_atom_matcher() = appCrashMatcher;
+
+ auto state = CreateUidProcessState();
+ *config.add_state() = state;
+
+ // Create count metric that slices by uid process state.
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(appCrashMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ countMetric->add_slice_by_state(state.id());
+ MetricStateLink* stateLink = countMetric->add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+ // Check that CountMetricProducer was initialized correctly.
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+ EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+
+ /*
+ NOTE: "1" or "2" represents the uid associated with the state/app crash event
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10
+ |------------------------|-------------------------|--
+ 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
+ -----------------------------------------------------PROCESS STATE events
+ 1 2 (TopEvent = 1002)
+ 1 1 (ForegroundServiceEvent = 1003)
+ 2 (ImportantBackgroundEvent = 1006)
+ 1 1 1 (ImportantForegroundEvent = 1005)
+
+ Based on the diagram above, an AppCrashEvent querying for process state value would return:
+ - StateTracker::kStateUnknown
+ - Important foreground
+ - Top
+ - Important foreground
+ - Foreground service
+ - Top (both the app crash and state still have matching uid = 2)
+
+ - Foreground service
+ - Foreground service
+ - Important background
+ */
+ // Initialize log events - first bucket.
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/)); // 2:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 2:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/)); // 3:30
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 210 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 3:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/)); // 4:20
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 4:50
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/)); // 4:55
+
+ // Initialize log events - second bucket.
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/)); // 6:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 390 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 6:40
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 430 * NS_PER_SEC, 2 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 7:20
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 440 * NS_PER_SEC, 1 /*uid*/)); // 7:30
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 9:10
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/)); // 9:40
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(3);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(4);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(2, data.bucket_info(1).count());
+}
+
+TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
+ // Initialize config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto appCrashMatcher =
+ CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+ *config.add_atom_matcher() = appCrashMatcher;
+
+ auto state1 = CreateScreenStateWithOnOffMap();
+ *config.add_state() = state1;
+ auto state2 = CreateUidProcessState();
+ *config.add_state() = state2;
+
+ // Create count metric that slices by screen state with on/off map and
+ // slices by uid process state.
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(appCrashMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ countMetric->add_slice_by_state(state1.id());
+ countMetric->add_slice_by_state(state2.id());
+ MetricStateLink* stateLink = countMetric->add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that StateTrackers were properly initialized.
+ EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+ // Check that CountMetricProducer was initialized correctly.
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+ EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+
+ StateMap map = state1.map();
+ for (auto group : map.group()) {
+ for (auto value : group.value()) {
+ EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
+ group.group_id());
+ }
+ }
+
+ /*
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10 (minutes)
+ |------------------------|------------------------|--
+ 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
+ ---------------------------------------------------SCREEN_OFF events
+ | (ScreenUnknownEvent = 0)
+ | | (ScreenOffEvent = 1)
+ | (ScreenDozeEvent = 3)
+ ---------------------------------------------------SCREEN_ON events
+ | | (ScreenOnEvent = 2)
+ | (ScreenOnSuspendEvent = 6)
+ ---------------------------------------------------PROCESS STATE events
+ 1 2 (TopEvent = 1002)
+ 1 (ForegroundServiceEvent = 1003)
+ 2 (ImportantBackgroundEvent = 1006)
+ 1 1 1 (ImportantForegroundEvent = 1005)
+
+ Based on the diagram above, Screen State / Process State pairs for each
+ AppCrashEvent are:
+ - StateTracker::kStateUnknown / important foreground
+ - off / important foreground
+ - off / Top
+ - on / important foreground
+ - off / important foreground
+ - off / top
+
+ - off / important foreground
+ - off / foreground service
+ - on / important background
+
+ */
+ // Initialize log events - first bucket.
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 5 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:15
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 30 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 0:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 90 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/)); // 2:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 2:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 160 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:50
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/)); // 3:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 210 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 3:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/)); // 4:20
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 4:50
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/)); // 4:55
+
+ // Initialize log events - second bucket.
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/)); // 6:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 380 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 6:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 390 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND)); // 6:40
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 420 * NS_PER_SEC, 2 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 7:10
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 440 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 7:30
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 450 * NS_PER_SEC, 1 /*uid*/)); // 7:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 520 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 8:50
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 9:10
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/)); // 9:40
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(-1, data.slice_by_state(0).value());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(3);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(4);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(5);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index 8eb5f69..b586b06 100644
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -26,688 +26,688 @@
#ifdef __ANDROID__
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(DurationMetricE2eTest, TestOneBucket) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-// *config.add_atom_matcher() = screenOnMatcher;
-// *config.add_atom_matcher() = screenOffMatcher;
-//
-// auto durationPredicate = CreateScreenIsOnPredicate();
-// *config.add_predicate() = durationPredicate;
-//
-// int64_t metricId = 123456;
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(metricId);
-// durationMetric->set_what(durationPredicate.id());
-// durationMetric->set_bucket(FIVE_MINUTES);
-// durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//
-// const int64_t baseTimeNs = 0; // 0:00
-// const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
-// const int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-//
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// // Screen is off at start of bucket.
-// event = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_OFF, configAddedTimeNs); // 0:01
-// processor->OnLogEvent(event.get());
-//
-// // Turn screen on.
-// const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-// processor->OnLogEvent(event.get());
-//
-// // Turn off screen 30 seconds after turning on.
-// const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-// processor->OnLogEvent(event.get());
-//
-// event = CreateScreenBrightnessChangedEvent(64, durationEndNs + 1 * NS_PER_SEC); // 0:42
-// processor->OnLogEvent(event.get());
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
-// ADB_DUMP, FAST, &buffer); // 5:01
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-//
-// const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
-// reports.reports(0).metrics(0).duration_metrics();
-// EXPECT_EQ(1, durationMetrics.data_size());
-//
-// auto data = durationMetrics.data(0);
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
-// EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestTwoBuckets) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-// *config.add_atom_matcher() = screenOnMatcher;
-// *config.add_atom_matcher() = screenOffMatcher;
-//
-// auto durationPredicate = CreateScreenIsOnPredicate();
-// *config.add_predicate() = durationPredicate;
-//
-// int64_t metricId = 123456;
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(metricId);
-// durationMetric->set_what(durationPredicate.id());
-// durationMetric->set_bucket(FIVE_MINUTES);
-// durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//
-// const int64_t baseTimeNs = 0; // 0:00
-// const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
-// const int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-//
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// // Screen is off at start of bucket.
-// event = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_OFF, configAddedTimeNs); // 0:01
-// processor->OnLogEvent(event.get());
-//
-// // Turn screen on.
-// const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-// processor->OnLogEvent(event.get());
-//
-// // Turn off screen 30 seconds after turning on.
-// const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-// processor->OnLogEvent(event.get());
-//
-// event = CreateScreenBrightnessChangedEvent(64, durationEndNs + 1 * NS_PER_SEC); // 0:42
-// processor->OnLogEvent(event.get());
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false, true,
-// ADB_DUMP, FAST, &buffer); // 10:01
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-//
-// const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
-// reports.reports(0).metrics(0).duration_metrics();
-// EXPECT_EQ(1, durationMetrics.data_size());
-//
-// auto data = durationMetrics.data(0);
-// EXPECT_EQ(1, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(0, bucketInfo.bucket_num());
-// EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
-// EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithActivation) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-// auto crashMatcher = CreateProcessCrashAtomMatcher();
-// *config.add_atom_matcher() = screenOnMatcher;
-// *config.add_atom_matcher() = screenOffMatcher;
-// *config.add_atom_matcher() = crashMatcher;
-//
-// auto durationPredicate = CreateScreenIsOnPredicate();
-// *config.add_predicate() = durationPredicate;
-//
-// int64_t metricId = 123456;
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(metricId);
-// durationMetric->set_what(durationPredicate.id());
-// durationMetric->set_bucket(FIVE_MINUTES);
-// durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-// auto metric_activation1 = config.add_metric_activation();
-// metric_activation1->set_metric_id(metricId);
-// auto event_activation1 = metric_activation1->add_event_activation();
-// event_activation1->set_atom_matcher_id(crashMatcher.id());
-// event_activation1->set_ttl_seconds(30); // 30 secs.
-//
-// const int64_t bucketStartTimeNs = 10000000000;
-// const int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap.size(), 1u);
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// // Turn screen off.
-// event = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 2 * NS_PER_SEC); // 0:02
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC);
-//
-// // Turn screen on.
-// const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:05
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-// processor.OnLogEvent(event.get(), durationStartNs);
-//
-// // Activate metric.
-// const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:10
-// const int64_t activationEndNs =
-// activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 0:40
-// event = CreateAppCrashEvent(111, activationStartNs);
-// processor.OnLogEvent(event.get(), activationStartNs);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// // Expire activation.
-// const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC;
-// event = CreateScreenBrightnessChangedEvent(64, expirationNs); // 0:47
-// processor.OnLogEvent(event.get(), expirationNs);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap.size(), 1u);
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// // Turn off screen 10 seconds after activation expiration.
-// const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC; // 0:50
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-// processor.OnLogEvent(event.get(),durationEndNs);
-//
-// // Turn screen on.
-// const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC; // 0:55
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, duration2StartNs);
-// processor.OnLogEvent(event.get(), duration2StartNs);
-//
-// // Turn off screen.
-// const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC; // 1:05
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, duration2EndNs);
-// processor.OnLogEvent(event.get(), duration2EndNs);
-//
-// // Activate metric.
-// const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC; // 1:10
-// const int64_t activation2EndNs =
-// activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 1:40
-// event = CreateAppCrashEvent(211, activation2StartNs);
-// processor.OnLogEvent(event.get(), activation2StartNs);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
-// ADB_DUMP, FAST, &buffer); // 5:01
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-//
-// const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
-// reports.reports(0).metrics(0).duration_metrics();
-// EXPECT_EQ(1, durationMetrics.data_size());
-//
-// auto data = durationMetrics.data(0);
-// EXPECT_EQ(1, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(0, bucketInfo.bucket_num());
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithCondition) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-//
-// auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-// *config.add_predicate() = holdingWakelockPredicate;
-//
-// auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-// *config.add_predicate() = isInBackgroundPredicate;
-//
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(StringToId("WakelockDuration"));
-// durationMetric->set_what(holdingWakelockPredicate.id());
-// durationMetric->set_condition(isInBackgroundPredicate.id());
-// durationMetric->set_aggregation_type(DurationMetric::SUM);
-// durationMetric->set_bucket(FIVE_MINUTES);
-//
-// ConfigKey cfgKey;
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_TRUE(eventActivationMap.empty());
-//
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-// auto event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10
-// processor->OnLogEvent(event.get());
-//
-// event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22
-// processor->OnLogEvent(event.get());
-//
-// event = CreateMoveToForegroundEvent(
-// appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15
-// processor->OnLogEvent(event.get());
-//
-// event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 4 * 60 * NS_PER_SEC); // 4:00
-// processor->OnLogEvent(event.get());
-//
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
-//
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//
-// // Validate bucket info.
-// EXPECT_EQ(1, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ((2 * 60 + 53) * NS_PER_SEC, bucketInfo.duration_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-//
-// auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-// // The predicate is dimensioning by first attribution node by uid.
-// FieldMatcher dimensions = CreateAttributionUidDimensions(
-// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-// *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
-// *config.add_predicate() = holdingWakelockPredicate;
-//
-// auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-// *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-// CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
-// *config.add_predicate() = isInBackgroundPredicate;
-//
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(StringToId("WakelockDuration"));
-// durationMetric->set_what(holdingWakelockPredicate.id());
-// durationMetric->set_condition(isInBackgroundPredicate.id());
-// durationMetric->set_aggregation_type(DurationMetric::SUM);
-// // The metric is dimensioning by first attribution node and only by uid.
-// *durationMetric->mutable_dimensions_in_what() =
-// CreateAttributionUidDimensions(
-// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-// durationMetric->set_bucket(FIVE_MINUTES);
-//
-// // Links between wakelock state atom and condition of app is in background.
-// auto links = durationMetric->add_links();
-// links->set_condition(isInBackgroundPredicate.id());
-// auto dimensionWhat = links->mutable_fields_in_what();
-// dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
-// dimensionWhat->add_child()->set_field(1); // uid field.
-// *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-// android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, { Position::FIRST });
-//
-// ConfigKey cfgKey;
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_TRUE(eventActivationMap.empty());
-//
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-// auto event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10
-// processor->OnLogEvent(event.get());
-//
-// event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22
-// processor->OnLogEvent(event.get());
-//
-// event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 60 * NS_PER_SEC); // 1:00
-// processor->OnLogEvent(event.get());
-//
-//
-// event = CreateMoveToForegroundEvent(
-// appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15
-// processor->OnLogEvent(event.get());
-//
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
-//
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, appUid);
-// // Validate bucket info.
-// EXPECT_EQ(1, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-// *config.add_atom_matcher() = screenOnMatcher;
-//
-// auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-// // The predicate is dimensioning by first attribution node by uid.
-// FieldMatcher dimensions = CreateAttributionUidDimensions(
-// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-// *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
-// *config.add_predicate() = holdingWakelockPredicate;
-//
-// auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-// *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-// CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
-// *config.add_predicate() = isInBackgroundPredicate;
-//
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(StringToId("WakelockDuration"));
-// durationMetric->set_what(holdingWakelockPredicate.id());
-// durationMetric->set_condition(isInBackgroundPredicate.id());
-// durationMetric->set_aggregation_type(DurationMetric::SUM);
-// // The metric is dimensioning by first attribution node and only by uid.
-// *durationMetric->mutable_dimensions_in_what() =
-// CreateAttributionUidDimensions(
-// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-// durationMetric->set_bucket(FIVE_MINUTES);
-//
-// // Links between wakelock state atom and condition of app is in background.
-// auto links = durationMetric->add_links();
-// links->set_condition(isInBackgroundPredicate.id());
-// auto dimensionWhat = links->mutable_fields_in_what();
-// dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
-// dimensionWhat->add_child()->set_field(1); // uid field.
-// *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-// android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, { Position::FIRST });
-//
-// auto metric_activation1 = config.add_metric_activation();
-// metric_activation1->set_metric_id(durationMetric->id());
-// auto event_activation1 = metric_activation1->add_event_activation();
-// event_activation1->set_atom_matcher_id(screenOnMatcher.id());
-// event_activation1->set_ttl_seconds(60 * 2); // 2 minutes.
-//
-// ConfigKey cfgKey;
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap.size(), 1u);
-// EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-// auto event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10
-// processor->OnLogEvent(event.get());
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22
-// processor->OnLogEvent(event.get());
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC; // 0:30
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-// processor->OnLogEvent(event.get());
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// const int64_t durationEndNs =
-// durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC; // 3:00
-// event = CreateAppCrashEvent(333, durationEndNs);
-// processor->OnLogEvent(event.get());
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// event = CreateMoveToForegroundEvent(
-// appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15
-// processor->OnLogEvent(event.get());
-//
-// event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC); // 4:17
-// processor->OnLogEvent(event.get());
-//
-// event = CreateMoveToBackgroundEvent(
-// appUid, bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC); // 4:20
-// processor->OnLogEvent(event.get());
-//
-// event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC); // 4:25
-// processor->OnLogEvent(event.get());
-//
-// const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC; // 4:30
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, duration2StartNs);
-// processor->OnLogEvent(event.get());
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
-//
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, appUid);
-// // Validate bucket info.
-// EXPECT_EQ(2, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
-//
-// bucketInfo = data.bucket_info(1);
-// EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos());
-//}
+TEST(DurationMetricE2eTest, TestOneBucket) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ auto durationPredicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = durationPredicate;
+
+ int64_t metricId = 123456;
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(metricId);
+ durationMetric->set_what(durationPredicate.id());
+ durationMetric->set_bucket(FIVE_MINUTES);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ const int64_t baseTimeNs = 0; // 0:00
+ const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
+ const int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
+
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+
+ std::unique_ptr<LogEvent> event;
+
+ // Screen is off at start of bucket.
+ event = CreateScreenStateChangedEvent(configAddedTimeNs,
+ android::view::DISPLAY_STATE_OFF); // 0:01
+ processor->OnLogEvent(event.get());
+
+ // Turn screen on.
+ const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
+ event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(event.get());
+
+ // Turn off screen 30 seconds after turning on.
+ const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
+ event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(event.get());
+
+ event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64); // 0:42
+ processor->OnLogEvent(event.get());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
+ ADB_DUMP, FAST, &buffer); // 5:01
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
+ reports.reports(0).metrics(0).duration_metrics();
+ EXPECT_EQ(1, durationMetrics.data_size());
+
+ auto data = durationMetrics.data(0);
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
+ EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestTwoBuckets) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ auto durationPredicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = durationPredicate;
+
+ int64_t metricId = 123456;
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(metricId);
+ durationMetric->set_what(durationPredicate.id());
+ durationMetric->set_bucket(FIVE_MINUTES);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ const int64_t baseTimeNs = 0; // 0:00
+ const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
+ const int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
+
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+
+ std::unique_ptr<LogEvent> event;
+
+ // Screen is off at start of bucket.
+ event = CreateScreenStateChangedEvent(configAddedTimeNs,
+ android::view::DISPLAY_STATE_OFF); // 0:01
+ processor->OnLogEvent(event.get());
+
+ // Turn screen on.
+ const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
+ event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(event.get());
+
+ // Turn off screen 30 seconds after turning on.
+ const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
+ event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(event.get());
+
+ event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64); // 0:42
+ processor->OnLogEvent(event.get());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false,
+ true, ADB_DUMP, FAST, &buffer); // 10:01
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
+ reports.reports(0).metrics(0).duration_metrics();
+ EXPECT_EQ(1, durationMetrics.data_size());
+
+ auto data = durationMetrics.data(0);
+ EXPECT_EQ(1, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(0, bucketInfo.bucket_num());
+ EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
+ EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithActivation) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ auto crashMatcher = CreateProcessCrashAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ *config.add_atom_matcher() = screenOffMatcher;
+ *config.add_atom_matcher() = crashMatcher;
+
+ auto durationPredicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = durationPredicate;
+
+ int64_t metricId = 123456;
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(metricId);
+ durationMetric->set_what(durationPredicate.id());
+ durationMetric->set_bucket(FIVE_MINUTES);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ auto metric_activation1 = config.add_metric_activation();
+ metric_activation1->set_metric_id(metricId);
+ auto event_activation1 = metric_activation1->add_event_activation();
+ event_activation1->set_atom_matcher_id(crashMatcher.id());
+ event_activation1->set_ttl_seconds(30); // 30 secs.
+
+ const int64_t bucketStartTimeNs = 10000000000;
+ const int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap.size(), 1u);
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ std::unique_ptr<LogEvent> event;
+
+ // Turn screen off.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * NS_PER_SEC,
+ android::view::DISPLAY_STATE_OFF); // 0:02
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC);
+
+ // Turn screen on.
+ const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:05
+ event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), durationStartNs);
+
+ // Activate metric.
+ const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:10
+ const int64_t activationEndNs =
+ activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 0:40
+ event = CreateAppCrashEvent(activationStartNs, 111);
+ processor.OnLogEvent(event.get(), activationStartNs);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ // Expire activation.
+ const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC;
+ event = CreateScreenBrightnessChangedEvent(expirationNs, 64); // 0:47
+ processor.OnLogEvent(event.get(), expirationNs);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap.size(), 1u);
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ // Turn off screen 10 seconds after activation expiration.
+ const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC; // 0:50
+ event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
+ processor.OnLogEvent(event.get(), durationEndNs);
+
+ // Turn screen on.
+ const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC; // 0:55
+ event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), duration2StartNs);
+
+ // Turn off screen.
+ const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC; // 1:05
+ event = CreateScreenStateChangedEvent(duration2EndNs, android::view::DISPLAY_STATE_OFF);
+ processor.OnLogEvent(event.get(), duration2EndNs);
+
+ // Activate metric.
+ const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC; // 1:10
+ const int64_t activation2EndNs =
+ activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 1:40
+ event = CreateAppCrashEvent(activation2StartNs, 211);
+ processor.OnLogEvent(event.get(), activation2StartNs);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
+ ADB_DUMP, FAST, &buffer); // 5:01
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
+ reports.reports(0).metrics(0).duration_metrics();
+ EXPECT_EQ(1, durationMetrics.data_size());
+
+ auto data = durationMetrics.data(0);
+ EXPECT_EQ(1, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(0, bucketInfo.bucket_num());
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithCondition) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+ auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_condition(isInBackgroundPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ durationMetric->set_bucket(FIVE_MINUTES);
+
+ ConfigKey cfgKey;
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_TRUE(eventActivationMap.empty());
+
+ int appUid = 123;
+ vector<int> attributionUids1 = {appUid};
+ vector<string> attributionTags1 = {"App1"};
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
+ attributionTags1,
+ "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
+ appUid); // 3:15
+ processor->OnLogEvent(event.get());
+
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 4 * 60 * NS_PER_SEC, attributionUids1,
+ attributionTags1,
+ "wl1"); // 4:00
+ processor->OnLogEvent(event.get());
+
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
+
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+
+ // Validate bucket info.
+ EXPECT_EQ(1, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ((2 * 60 + 53) * NS_PER_SEC, bucketInfo.duration_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+ auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid.
+ FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED,
+ {Position::FIRST});
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_condition(isInBackgroundPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ // The metric is dimensioning by first attribution node and only by uid.
+ *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+ android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ durationMetric->set_bucket(FIVE_MINUTES);
+
+ // Links between wakelock state atom and condition of app is in background.
+ auto links = durationMetric->add_links();
+ links->set_condition(isInBackgroundPredicate.id());
+ auto dimensionWhat = links->mutable_fields_in_what();
+ dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
+ dimensionWhat->add_child()->set_field(1); // uid field.
+ *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
+ android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+
+ ConfigKey cfgKey;
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_TRUE(eventActivationMap.empty());
+
+ int appUid = 123;
+ std::vector<int> attributionUids1 = {appUid};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22
+ processor->OnLogEvent(event.get());
+
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 1:00
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
+ appUid); // 3:15
+ processor->OnLogEvent(event.get());
+
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
+
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, appUid);
+ // Validate bucket info.
+ EXPECT_EQ(1, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+
+ auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid.
+ FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED,
+ {Position::FIRST});
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_condition(isInBackgroundPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ // The metric is dimensioning by first attribution node and only by uid.
+ *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+ android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ durationMetric->set_bucket(FIVE_MINUTES);
+
+ // Links between wakelock state atom and condition of app is in background.
+ auto links = durationMetric->add_links();
+ links->set_condition(isInBackgroundPredicate.id());
+ auto dimensionWhat = links->mutable_fields_in_what();
+ dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
+ dimensionWhat->add_child()->set_field(1); // uid field.
+ *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
+ android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+
+ auto metric_activation1 = config.add_metric_activation();
+ metric_activation1->set_metric_id(durationMetric->id());
+ auto event_activation1 = metric_activation1->add_event_activation();
+ event_activation1->set_atom_matcher_id(screenOnMatcher.id());
+ event_activation1->set_ttl_seconds(60 * 2); // 2 minutes.
+
+ ConfigKey cfgKey;
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap.size(), 1u);
+ EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ int appUid = 123;
+ std::vector<int> attributionUids1 = {appUid};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC; // 0:30
+ event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ const int64_t durationEndNs =
+ durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC; // 3:00
+ event = CreateAppCrashEvent(durationEndNs, 333);
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
+ appUid); // 3:15
+ processor->OnLogEvent(event.get());
+
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1"); // 4:17
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC,
+ appUid); // 4:20
+ processor->OnLogEvent(event.get());
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1"); // 4:25
+ processor->OnLogEvent(event.get());
+
+ const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC; // 4:30
+ event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
+
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, appUid);
+ // Validate bucket info.
+ EXPECT_EQ(2, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
+
+ bucketInfo = data.bucket_info(1);
+ EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos());
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 7f651d4..594c1e6 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -65,482 +65,465 @@
} // namespaces
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
-// auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// ATOM_TAG);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// // When creating the config, the gauge metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& nextPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-//
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// // Pulling alarm arrives on time and reset the sequential pulling alarm.
-// processor->informPullAlarmFired(nextPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + bucketSizeNs + 10);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + bucketSizeNs + 100);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
-// nextPullTimeNs);
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
-//
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 3 * bucketSizeNs + 2);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 3);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 5 * bucketSizeNs + 1);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 2);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs);
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 2);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_GT((int)gaugeMetrics.data_size(), 1);
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(6, data.bucket_info_size());
-//
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1,
-// data.bucket_info(1).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(2).atom_size());
-// EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1,
-// data.bucket_info(2).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(3).atom_size());
-// EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1,
-// data.bucket_info(3).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(4).atom_size());
-// EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1,
-// data.bucket_info(4).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(5).atom_size());
-// EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2,
-// data.bucket_info(5).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(5).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(5).atom(0).subsystem_sleep_state().time_millis(), 0);
-//}
-//
-//TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
-// auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// ATOM_TAG);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + bucketSizeNs + 10);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + bucketSizeNs + 100);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 3 * bucketSizeNs + 2);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 5 * bucketSizeNs + 1);
-// processor->OnLogEvent(screenOffEvent.get());
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 5 * bucketSizeNs + 3);
-// processor->OnLogEvent(screenOnEvent.get());
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 5 * bucketSizeNs + 10);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_GT((int)gaugeMetrics.data_size(), 1);
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(3, data.bucket_info_size());
-//
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100,
-// data.bucket_info(1).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(2, data.bucket_info(2).atom_size());
-// EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1,
-// data.bucket_info(2).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10,
-// data.bucket_info(2).elapsed_timestamp_nanos(1));
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-// EXPECT_TRUE(data.bucket_info(2).atom(1).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(2).atom(1).subsystem_sleep_state().time_millis(), 0);
-//}
-//
-//
-//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
-// auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// ATOM_TAG);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// // When creating the config, the gauge metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& nextPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-//
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + bucketSizeNs + 10);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// // Pulling alarm arrives one bucket size late.
-// processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 3 * bucketSizeNs + 11);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// // Pulling alarm arrives more than one bucket size late.
-// processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_GT((int)gaugeMetrics.data_size(), 1);
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(3, data.bucket_info_size());
-//
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
-// data.bucket_info(1).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(2).atom_size());
-// EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12,
-// data.bucket_info(2).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-//}
-//
-//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) {
-// auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
-//
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
-// *config.add_atom_matcher() = batterySaverStartMatcher;
-// const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
-// auto metric_activation = config.add_metric_activation();
-// metric_activation->set_metric_id(metricId);
-// metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-// auto event_activation = metric_activation->add_event_activation();
-// event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
-// event_activation->set_ttl_seconds(ttlNs / 1000000000);
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// ATOM_TAG);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // When creating the config, the gauge metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& nextPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-//
-// // Pulling alarm arrives on time and reset the sequential pulling alarm.
-// // Event should not be kept.
-// processor->informPullAlarmFired(nextPullTimeNs + 1); // 15 mins + 1 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // Activate the metric. A pull occurs upon activation.
-// const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
-// auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
-// processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // This event should be kept. 2 total.
-// processor->informPullAlarmFired(nextPullTimeNs + 1); // 20 mins + 1 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
-// nextPullTimeNs);
-//
-// // This event should be kept. 3 total.
-// processor->informPullAlarmFired(nextPullTimeNs + 2); // 25 mins + 2 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
-//
-// // Create random event to deactivate metric.
-// auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1);
-// processor->OnLogEvent(deactivationEvent.get());
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // Event should not be kept. 3 total.
-// processor->informPullAlarmFired(nextPullTimeNs + 3);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 2);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_GT((int)gaugeMetrics.data_size(), 0);
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(3, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(1, bucketInfo.atom_size());
-// EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-// EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// bucketInfo = data.bucket_info(1);
-// EXPECT_EQ(1, bucketInfo.atom_size());
-// EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// bucketInfo = data.bucket_info(2);
-// EXPECT_EQ(1, bucketInfo.atom_size());
-// EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)),
-// bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)),
-// bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-//}
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
+ auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ // When creating the config, the gauge metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& nextPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(nextPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
+
+ auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ processor->informPullAlarmFired(nextPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+ processor->informPullAlarmFired(nextPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
+
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ processor->informPullAlarmFired(nextPullTimeNs + 3);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ processor->informPullAlarmFired(nextPullTimeNs + 2);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs);
+
+ processor->informPullAlarmFired(nextPullTimeNs + 2);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(6, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(3).atom_size());
+ EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1, data.bucket_info(3).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(4).atom_size());
+ EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(4).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(5).atom_size());
+ EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2, data.bucket_info(5).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(5).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(5).atom(0).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
+ auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 3,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 10,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(3, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100, data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(2, data.bucket_info(2).atom_size());
+ EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10, data.bucket_info(2).elapsed_timestamp_nanos(1));
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+ EXPECT_TRUE(data.bucket_info(2).atom(1).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(2).atom(1).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
+ auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ // When creating the config, the gauge metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& nextPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ // Pulling alarm arrives one bucket size late.
+ processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 11,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ // Pulling alarm arrives more than one bucket size late.
+ processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(3, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
+ data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12, data.bucket_info(2).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) {
+ auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
+
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
+ *config.add_atom_matcher() = batterySaverStartMatcher;
+ const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
+ auto metric_activation = config.add_metric_activation();
+ metric_activation->set_metric_id(metricId);
+ metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
+ auto event_activation = metric_activation->add_event_activation();
+ event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
+ event_activation->set_ttl_seconds(ttlNs / 1000000000);
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // When creating the config, the gauge metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& nextPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ // Event should not be kept.
+ processor->informPullAlarmFired(nextPullTimeNs + 1); // 15 mins + 1 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // Activate the metric. A pull occurs upon activation.
+ const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
+ auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
+ processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // This event should be kept. 2 total.
+ processor->informPullAlarmFired(nextPullTimeNs + 1); // 20 mins + 1 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+ // This event should be kept. 3 total.
+ processor->informPullAlarmFired(nextPullTimeNs + 2); // 25 mins + 2 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
+
+ // Create random event to deactivate metric.
+ auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50);
+ processor->OnLogEvent(deactivationEvent.get());
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // Event should not be kept. 3 total.
+ processor->informPullAlarmFired(nextPullTimeNs + 3);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+ processor->informPullAlarmFired(nextPullTimeNs + 2);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 0);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(3, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(1, bucketInfo.atom_size());
+ EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+ EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ bucketInfo = data.bucket_info(1);
+ EXPECT_EQ(1, bucketInfo.atom_size());
+ EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ bucketInfo = data.bucket_info(2);
+ EXPECT_EQ(1, bucketInfo.atom_size());
+ EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)),
+ bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)),
+ bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
+}
TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition) {
auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index ef6e753..6e3d93a 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -14,12 +14,13 @@
#include <gtest/gtest.h>
+#include <vector>
+
#include "src/StatsLogProcessor.h"
#include "src/stats_log_util.h"
+#include "stats_event.h"
#include "tests/statsd_test_util.h"
-#include <vector>
-
namespace android {
namespace os {
namespace statsd {
@@ -68,221 +69,227 @@
return config;
}
-// TODO(b/149590301): Update this helper to use new socket schema.
-//std::unique_ptr<LogEvent> CreateAppStartOccurredEvent(
-// const int uid, const string& pkg_name, AppStartOccurred::TransitionType type,
-// const string& activity_name, const string& calling_pkg_name, const bool is_instant_app,
-// int64_t activity_start_msec, uint64_t timestampNs) {
-// auto logEvent = std::make_unique<LogEvent>(
-// android::util::APP_START_OCCURRED, timestampNs);
-// logEvent->write(uid);
-// logEvent->write(pkg_name);
-// logEvent->write(type);
-// logEvent->write(activity_name);
-// logEvent->write(calling_pkg_name);
-// logEvent->write(is_instant_app);
-// logEvent->write(activity_start_msec);
-// logEvent->init();
-// return logEvent;
-//}
+std::unique_ptr<LogEvent> CreateAppStartOccurredEvent(
+ uint64_t timestampNs, const int uid, const string& pkg_name,
+ AppStartOccurred::TransitionType type, const string& activity_name,
+ const string& calling_pkg_name, const bool is_instant_app, int64_t activity_start_msec) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::APP_START_OCCURRED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, pkg_name.c_str());
+ AStatsEvent_writeInt32(statsEvent, type);
+ AStatsEvent_writeString(statsEvent, activity_name.c_str());
+ AStatsEvent_writeString(statsEvent, calling_pkg_name.c_str());
+ AStatsEvent_writeInt32(statsEvent, is_instant_app);
+ AStatsEvent_writeInt32(statsEvent, activity_start_msec);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
} // namespace
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
-// for (const auto& sampling_type :
-// { GaugeMetric::FIRST_N_SAMPLES, GaugeMetric:: RANDOM_ONE_SAMPLE }) {
-// auto config = CreateStatsdConfigForPushedEvent(sampling_type);
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(
-// bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// int appUid1 = 123;
-// int appUid2 = 456;
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + 15));
-// events.push_back(CreateMoveToForegroundEvent(
-// appUid1, bucketStartTimeNs + bucketSizeNs + 250));
-// events.push_back(CreateMoveToBackgroundEvent(
-// appUid1, bucketStartTimeNs + bucketSizeNs + 350));
-// events.push_back(CreateMoveToForegroundEvent(
-// appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100));
-//
-//
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::WARM, "activity_name1", "calling_pkg_name1",
-// true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::HOT, "activity_name2", "calling_pkg_name2",
-// true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::COLD, "activity_name3", "calling_pkg_name3",
-// true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::WARM, "activity_name4", "calling_pkg_name4",
-// true /*is_instant_app*/, 104 /*activity_start_msec*/,
-// bucketStartTimeNs + bucketSizeNs + 30));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::COLD, "activity_name5", "calling_pkg_name5",
-// true /*is_instant_app*/, 105 /*activity_start_msec*/,
-// bucketStartTimeNs + 2 * bucketSizeNs));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::HOT, "activity_name6", "calling_pkg_name6",
-// false /*is_instant_app*/, 106 /*activity_start_msec*/,
-// bucketStartTimeNs + 2 * bucketSizeNs + 10));
-//
-// events.push_back(CreateMoveToBackgroundEvent(
-// appUid2, bucketStartTimeNs + bucketSizeNs + 10));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid2, "app2", AppStartOccurred::COLD, "activity_name7", "calling_pkg_name7",
-// true /*is_instant_app*/, 201 /*activity_start_msec*/,
-// bucketStartTimeNs + 2 * bucketSizeNs + 10));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_EQ(2, gaugeMetrics.data_size());
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(3, data.bucket_info_size());
-// if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
-// EXPECT_EQ(2, data.bucket_info(0).atom_size());
-// EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::HOT,
-// data.bucket_info(0).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name2",
-// data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(102L,
-// data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-// EXPECT_EQ(AppStartOccurred::COLD,
-// data.bucket_info(0).atom(1).app_start_occurred().type());
-// EXPECT_EQ("activity_name3",
-// data.bucket_info(0).atom(1).app_start_occurred().activity_name());
-// EXPECT_EQ(103L,
-// data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::WARM,
-// data.bucket_info(1).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name4",
-// data.bucket_info(1).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(104L,
-// data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
-//
-// EXPECT_EQ(2, data.bucket_info(2).atom_size());
-// EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::COLD,
-// data.bucket_info(2).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name5",
-// data.bucket_info(2).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(105L,
-// data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
-// EXPECT_EQ(AppStartOccurred::HOT,
-// data.bucket_info(2).atom(1).app_start_occurred().type());
-// EXPECT_EQ("activity_name6",
-// data.bucket_info(2).atom(1).app_start_occurred().activity_name());
-// EXPECT_EQ(106L,
-// data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
-// } else {
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::HOT,
-// data.bucket_info(0).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name2",
-// data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(102L,
-// data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::WARM,
-// data.bucket_info(1).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name4",
-// data.bucket_info(1).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(104L,
-// data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
-//
-// EXPECT_EQ(1, data.bucket_info(2).atom_size());
-// EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::COLD,
-// data.bucket_info(2).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name5",
-// data.bucket_info(2).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(105L,
-// data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
-// }
-//
-// data = gaugeMetrics.data(1);
-//
-// EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name7",
-// data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-// }
-//}
+TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
+ for (const auto& sampling_type :
+ {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) {
+ auto config = CreateStatsdConfigForPushedEvent(sampling_type);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ int appUid1 = 123;
+ int appUid2 = 456;
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid1));
+ events.push_back(
+ CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid1));
+ events.push_back(
+ CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid1));
+ events.push_back(
+ CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, appUid1));
+
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 10, appUid1, "app1", AppStartOccurred::WARM, "activity_name1",
+ "calling_pkg_name1", true /*is_instant_app*/, 101 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 20, appUid1, "app1", AppStartOccurred::HOT, "activity_name2",
+ "calling_pkg_name2", true /*is_instant_app*/, 102 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 30, appUid1, "app1", AppStartOccurred::COLD, "activity_name3",
+ "calling_pkg_name3", true /*is_instant_app*/, 103 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + bucketSizeNs + 30, appUid1, "app1", AppStartOccurred::WARM,
+ "activity_name4", "calling_pkg_name4", true /*is_instant_app*/,
+ 104 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 2 * bucketSizeNs, appUid1, "app1", AppStartOccurred::COLD,
+ "activity_name5", "calling_pkg_name5", true /*is_instant_app*/,
+ 105 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid1, "app1", AppStartOccurred::HOT,
+ "activity_name6", "calling_pkg_name6", false /*is_instant_app*/,
+ 106 /*activity_start_msec*/));
+
+ events.push_back(
+ CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 10, appUid2));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid2, "app2", AppStartOccurred::COLD,
+ "activity_name7", "calling_pkg_name7", true /*is_instant_app*/,
+ 201 /*activity_start_msec*/));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
+ &gaugeMetrics);
+ EXPECT_EQ(2, gaugeMetrics.data_size());
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(3, data.bucket_info_size());
+ if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
+ EXPECT_EQ(2, data.bucket_info(0).atom_size());
+ EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::HOT,
+ data.bucket_info(0).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name2",
+ data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(102L,
+ data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+ EXPECT_EQ(AppStartOccurred::COLD,
+ data.bucket_info(0).atom(1).app_start_occurred().type());
+ EXPECT_EQ("activity_name3",
+ data.bucket_info(0).atom(1).app_start_occurred().activity_name());
+ EXPECT_EQ(103L,
+ data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::WARM,
+ data.bucket_info(1).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name4",
+ data.bucket_info(1).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(104L,
+ data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
+
+ EXPECT_EQ(2, data.bucket_info(2).atom_size());
+ EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::COLD,
+ data.bucket_info(2).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name5",
+ data.bucket_info(2).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(105L,
+ data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
+ EXPECT_EQ(AppStartOccurred::HOT,
+ data.bucket_info(2).atom(1).app_start_occurred().type());
+ EXPECT_EQ("activity_name6",
+ data.bucket_info(2).atom(1).app_start_occurred().activity_name());
+ EXPECT_EQ(106L,
+ data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
+ } else {
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::HOT,
+ data.bucket_info(0).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name2",
+ data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(102L,
+ data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::WARM,
+ data.bucket_info(1).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name4",
+ data.bucket_info(1).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(104L,
+ data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::COLD,
+ data.bucket_info(2).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name5",
+ data.bucket_info(2).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(105L,
+ data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
+ }
+
+ data = gaugeMetrics.data(1);
+
+ EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name7",
+ data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+ }
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index f3f7df77..1dd90e2 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -233,1609 +233,1602 @@
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(MetricActivationE2eTest, TestCountMetric) {
-// auto config = CreateStatsdConfig();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// // Activated by battery save mode.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// // First processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Activated by screen on event.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 20);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// // 2nd processed event.
-// // The activation by screen_on event expires, but the one by battery save mode is still active.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// // No new broadcast since the config should still be active.
-// EXPECT_EQ(broadcastCount, 1);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-// // All activations expired.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// // Re-activate metric via screen on.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// // 4th processed event.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(4, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) {
-// auto config = CreateStatsdConfigWithOneDeactivation();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap.size(), 1u);
-// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// // Activated by battery save mode.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // First processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Activated by screen on event.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 20);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // 2nd processed event.
-// // The activation by screen_on event expires, but the one by battery save mode is still active.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// // No new broadcast since the config should still be active.
-// EXPECT_EQ(broadcastCount, 1);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-// // All activations expired.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // Re-activate metric via screen on.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // 4th processed event.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // 5th processed event.
-// event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//
-// // Cancel battery saver mode activation.
-// event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // Screen-on activation expired.
-// event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 5);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // Cancel battery saver mode activation.
-// event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 6);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(5, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) {
-// auto config = CreateStatsdConfigWithTwoDeactivations();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap.size(), 2u);
-// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-// EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// // Activated by battery save mode.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // First processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Activated by screen on event.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 20);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // 2nd processed event.
-// // The activation by screen_on event expires, but the one by battery save mode is still active.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// // No new broadcast since the config should still be active.
-// EXPECT_EQ(broadcastCount, 1);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-// // All activations expired.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // Re-activate metric via screen on.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // 4th processed event.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // 5th processed event.
-// event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//
-// // Cancel battery saver mode and screen on activation.
-// event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // Screen-on activation expired.
-// event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 5);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // Cancel battery saver mode and screen on activation.
-// event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 6);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(5, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) {
-// auto config = CreateStatsdConfigWithSameDeactivations();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap.size(), 1u);
-// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 2u);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// // Event that should be ignored.
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 1);
-//
-// // Activate metric via screen on for 2 minutes.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
-//
-// // 1st processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Enable battery saver mode activation for 5 minutes.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
-//
-// // 2nd processed event.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40);
-//
-// // Cancel battery saver mode and screen on activation.
-// int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61;
-// event = CreateScreenBrightnessChangedEvent(64, firstDeactivation);
-// processor.OnLogEvent(event.get(), firstDeactivation);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//
-// // Should be ignored
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 61 + 80);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
-//
-// // Cancel battery saver mode activation.
-// int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13;
-// event = CreateScreenBrightnessChangedEvent(140, secondDeactivation);
-// processor.OnLogEvent(event.get(), secondDeactivation);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//
-// // Should be ignored.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(3, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(secondDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) {
-// auto config = CreateStatsdConfigWithTwoMetricsTwoDeactivations();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 2);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-// sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1];
-// auto& eventActivationMap2 = metricProducer2->mEventActivationMap;
-// auto& eventDeactivationMap2 = metricProducer2->mEventDeactivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap.size(), 2u);
-// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-// EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// EXPECT_EQ(eventActivationMap2.size(), 2u);
-// EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end());
-// EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end());
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2.size(), 2u);
-// EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end());
-// EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// event = CreateMoveToForegroundEvent(1111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// // Activated by battery save mode.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // First processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-// event = CreateMoveToForegroundEvent(2222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Activated by screen on event.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 20);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // 2nd processed event.
-// // The activation by screen_on event expires, but the one by battery save mode is still active.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// event = CreateMoveToForegroundEvent(3333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-// // No new broadcast since the config should still be active.
-// EXPECT_EQ(broadcastCount, 1);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// event = CreateMoveToForegroundEvent(4444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-// // All activations expired.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// event = CreateMoveToForegroundEvent(5555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// EXPECT_FALSE(metricsManager->isActive());
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // Re-activate metric via screen on.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // 4th processed event.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// event = CreateMoveToForegroundEvent(6666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // 5th processed event.
-// event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// event = CreateMoveToForegroundEvent(7777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//
-// // Cancel battery saver mode and screen on activation.
-// event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// EXPECT_FALSE(metricsManager->isActive());
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // Screen-on activation expired.
-// event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// event = CreateMoveToForegroundEvent(8888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// event = CreateMoveToForegroundEvent(9999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 5);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // Cancel battery saver mode and screen on activation.
-// event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 6);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(2, reports.reports(0).metrics_size());
-// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-// EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-//
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(5, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//
-// countMetrics.clear_data();
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(1).count_metrics(), &countMetrics);
-// EXPECT_EQ(5, countMetrics.data_size());
-//
-// data = countMetrics.data(0);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
+TEST(MetricActivationE2eTest, TestCountMetric) {
+ auto config = CreateStatsdConfig();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // First processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+ // All activations expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // Re-activate metric via screen on.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // 4th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(4, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) {
+ auto config = CreateStatsdConfigWithOneDeactivation();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap.size(), 1u);
+ EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // First processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+ // All activations expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // Re-activate metric via screen on.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // 4th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // 5th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+
+ // Cancel battery saver mode activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // Screen-on activation expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 5);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // Cancel battery saver mode activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 6);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(5, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) {
+ auto config = CreateStatsdConfigWithTwoDeactivations();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap.size(), 2u);
+ EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+ EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // First processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+ // All activations expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // Re-activate metric via screen on.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // 4th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // 5th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+
+ // Cancel battery saver mode and screen on activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // Screen-on activation expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 5);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // Cancel battery saver mode and screen on activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 6);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(5, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) {
+ auto config = CreateStatsdConfigWithSameDeactivations();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap.size(), 1u);
+ EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 2u);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]);
+ EXPECT_EQ(broadcastCount, 0);
+
+ std::unique_ptr<LogEvent> event;
+
+ // Event that should be ignored.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 1, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 1);
+
+ // Activate metric via screen on for 2 minutes.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 10, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
+
+ // 1st processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Enable battery saver mode activation for 5 minutes.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 + 10);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
+
+ // 2nd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 40, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40);
+
+ // Cancel battery saver mode and screen on activation.
+ int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61;
+ event = CreateScreenBrightnessChangedEvent(firstDeactivation, 64);
+ processor.OnLogEvent(event.get(), firstDeactivation);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+
+ // Should be ignored
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 61 + 80, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
+
+ // Cancel battery saver mode activation.
+ int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13;
+ event = CreateScreenBrightnessChangedEvent(secondDeactivation, 140);
+ processor.OnLogEvent(event.get(), secondDeactivation);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+
+ // Should be ignored.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(3, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(secondDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) {
+ auto config = CreateStatsdConfigWithTwoMetricsTwoDeactivations();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 2);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+ sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1];
+ auto& eventActivationMap2 = metricProducer2->mEventActivationMap;
+ auto& eventDeactivationMap2 = metricProducer2->mEventDeactivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap.size(), 2u);
+ EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+ EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ EXPECT_EQ(eventActivationMap2.size(), 2u);
+ EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end());
+ EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end());
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2.size(), 2u);
+ EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end());
+ EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + 5, 1111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // First processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + 15, 2222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 3333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 4444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+ // All activations expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 5555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ EXPECT_FALSE(metricsManager->isActive());
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // Re-activate metric via screen on.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // 4th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 6666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // 5th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 7777);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+
+ // Cancel battery saver mode and screen on activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
+ EXPECT_FALSE(metricsManager->isActive());
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // Screen-on activation expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 8888);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 9999);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 5);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // Cancel battery saver mode and screen on activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 6);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(2, reports.reports(0).metrics_size());
+ EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+ EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(5, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ countMetrics.clear_data();
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(1).count_metrics(), &countMetrics);
+ EXPECT_EQ(5, countMetrics.data_size());
+
+ data = countMetrics.data(0);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 7d93fcc..e8fb523 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -97,250 +97,247 @@
}
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
-//// we should use the real API which will clear the data after dump data is called.
-//TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
-// auto config = CreateStatsdConfig();
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// int appUid = 123;
-// auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1);
-// auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201);
-// auto crashEvent3= CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101);
-//
-// auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51);
-// auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299);
-// auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001);
-//
-// auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16);
-// auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249);
-//
-// auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351);
-// auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
-//
-// auto screenTurnedOnEvent =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2);
-// auto screenTurnedOffEvent =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 200);
-// auto screenTurnedOnEvent2 =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2 * bucketSizeNs - 100);
-//
-// std::vector<AttributionNodeInternal> attributions = {
-// CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")};
-// auto syncOnEvent1 =
-// CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50);
-// auto syncOffEvent1 =
-// CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300);
-// auto syncOnEvent2 =
-// CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000);
-//
-// auto moveToBackgroundEvent1 =
-// CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15);
-// auto moveToForegroundEvent1 =
-// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250);
-//
-// auto moveToBackgroundEvent2 =
-// CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350);
-// auto moveToForegroundEvent2 =
-// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1);
-//
-// /*
-// bucket #1 bucket #2
-//
-//
-// | | | | | | | | | | (crashEvents)
-// |-------------------------------------|-----------------------------------|---------
-//
-// | | (MoveToBkground)
-//
-// | | (MoveToForeground)
-//
-// | | (SyncIsOn)
-// | (SyncIsOff)
-// | | (ScreenIsOn)
-// | (ScreenIsOff)
-// */
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(std::move(crashEvent1));
-// events.push_back(std::move(crashEvent2));
-// events.push_back(std::move(crashEvent3));
-// events.push_back(std::move(crashEvent4));
-// events.push_back(std::move(crashEvent5));
-// events.push_back(std::move(crashEvent6));
-// events.push_back(std::move(crashEvent7));
-// events.push_back(std::move(crashEvent8));
-// events.push_back(std::move(crashEvent9));
-// events.push_back(std::move(crashEvent10));
-// events.push_back(std::move(screenTurnedOnEvent));
-// events.push_back(std::move(screenTurnedOffEvent));
-// events.push_back(std::move(screenTurnedOnEvent2));
-// events.push_back(std::move(syncOnEvent1));
-// events.push_back(std::move(syncOffEvent1));
-// events.push_back(std::move(syncOnEvent2));
-// events.push_back(std::move(moveToBackgroundEvent1));
-// events.push_back(std::move(moveToForegroundEvent1));
-// events.push_back(std::move(moveToBackgroundEvent2));
-// events.push_back(std::move(moveToForegroundEvent2));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// // Validate dimension value.
-// EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
-// // Uid field.
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
-//}
-//
-//TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
-// auto config = CreateStatsdConfig();
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(
-// bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// int appUid = 123;
-// auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1);
-// auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201);
-// auto crashEvent3 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101);
-//
-// auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51);
-// auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299);
-// auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001);
-//
-// auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16);
-// auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249);
-//
-// auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351);
-// auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
-//
-// auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 2);
-// auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200);
-// auto screenTurnedOnEvent2 =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2 * bucketSizeNs - 100);
-//
-// std::vector<AttributionNodeInternal> attributions = {
-// CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")};
-// auto syncOnEvent1 = CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50);
-// auto syncOffEvent1 =
-// CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300);
-// auto syncOnEvent2 =
-// CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000);
-//
-// auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15);
-// auto moveToForegroundEvent1 =
-// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250);
-//
-// auto moveToBackgroundEvent2 =
-// CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350);
-// auto moveToForegroundEvent2 =
-// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1);
-//
-// /*
-// bucket #1 bucket #2
-//
-//
-// | | | | | | | | | | (crashEvents)
-// |-------------------------------------|-----------------------------------|---------
-//
-// | | (MoveToBkground)
-//
-// | | (MoveToForeground)
-//
-// | | (SyncIsOn)
-// | (SyncIsOff)
-// | | (ScreenIsOn)
-// | (ScreenIsOff)
-// */
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(std::move(crashEvent1));
-// events.push_back(std::move(crashEvent2));
-// events.push_back(std::move(crashEvent3));
-// events.push_back(std::move(crashEvent4));
-// events.push_back(std::move(crashEvent5));
-// events.push_back(std::move(crashEvent6));
-// events.push_back(std::move(crashEvent7));
-// events.push_back(std::move(crashEvent8));
-// events.push_back(std::move(crashEvent9));
-// events.push_back(std::move(crashEvent10));
-// events.push_back(std::move(screenTurnedOnEvent));
-// events.push_back(std::move(screenTurnedOffEvent));
-// events.push_back(std::move(screenTurnedOnEvent2));
-// events.push_back(std::move(syncOnEvent1));
-// events.push_back(std::move(syncOffEvent1));
-// events.push_back(std::move(syncOnEvent2));
-// events.push_back(std::move(moveToBackgroundEvent1));
-// events.push_back(std::move(moveToForegroundEvent1));
-// events.push_back(std::move(moveToBackgroundEvent2));
-// events.push_back(std::move(moveToForegroundEvent2));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-//
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// // Validate dimension value.
-// EXPECT_EQ(data.dimensions_in_what().field(),
-// android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
-// // Uid field.
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
-//}
+// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
+// we should use the real API which will clear the data after dump data is called.
+TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
+ auto config = CreateStatsdConfig();
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ int appUid = 123;
+ auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
+ auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
+ auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
+
+ auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
+ auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
+ auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
+
+ auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
+ auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
+
+ auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
+ auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
+
+ auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ auto screenTurnedOnEvent2 =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+ std::vector<int> attributionUids = {appUid, appUid + 1};
+ std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
+
+ auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
+ attributionTags, "ReadEmail");
+ auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
+ attributionTags, "ReadEmail");
+ auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
+ attributionUids, attributionTags, "ReadDoc");
+
+ auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
+ auto moveToForegroundEvent1 =
+ CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
+
+ auto moveToBackgroundEvent2 =
+ CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
+ auto moveToForegroundEvent2 =
+ CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
+
+ /*
+ bucket #1 bucket #2
+
+
+ | | | | | | | | | | (crashEvents)
+ |-------------------------------------|-----------------------------------|---------
+
+ | | (MoveToBkground)
+
+ | | (MoveToForeground)
+
+ | | (SyncIsOn)
+ | (SyncIsOff)
+ | | (ScreenIsOn)
+ | (ScreenIsOff)
+ */
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(std::move(crashEvent1));
+ events.push_back(std::move(crashEvent2));
+ events.push_back(std::move(crashEvent3));
+ events.push_back(std::move(crashEvent4));
+ events.push_back(std::move(crashEvent5));
+ events.push_back(std::move(crashEvent6));
+ events.push_back(std::move(crashEvent7));
+ events.push_back(std::move(crashEvent8));
+ events.push_back(std::move(crashEvent9));
+ events.push_back(std::move(crashEvent10));
+ events.push_back(std::move(screenTurnedOnEvent));
+ events.push_back(std::move(screenTurnedOffEvent));
+ events.push_back(std::move(screenTurnedOnEvent2));
+ events.push_back(std::move(syncOnEvent1));
+ events.push_back(std::move(syncOffEvent1));
+ events.push_back(std::move(syncOnEvent2));
+ events.push_back(std::move(moveToBackgroundEvent1));
+ events.push_back(std::move(moveToForegroundEvent1));
+ events.push_back(std::move(moveToBackgroundEvent2));
+ events.push_back(std::move(moveToForegroundEvent2));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ // Validate dimension value.
+ EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ // Uid field.
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
+}
+
+TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
+ auto config = CreateStatsdConfig();
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ int appUid = 123;
+ auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
+ auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
+ auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
+
+ auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
+ auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
+ auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
+
+ auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
+ auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
+
+ auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
+ auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
+
+ auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ auto screenTurnedOnEvent2 =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+ std::vector<int> attributionUids = {appUid, appUid + 1};
+ std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
+
+ auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
+ attributionTags, "ReadEmail");
+ auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
+ attributionTags, "ReadEmail");
+ auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
+ attributionUids, attributionTags, "ReadDoc");
+
+ auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
+ auto moveToForegroundEvent1 =
+ CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
+
+ auto moveToBackgroundEvent2 =
+ CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
+ auto moveToForegroundEvent2 =
+ CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
+
+ /*
+ bucket #1 bucket #2
+
+
+ | | | | | | | | | | (crashEvents)
+ |-------------------------------------|-----------------------------------|---------
+
+ | | (MoveToBkground)
+
+ | | (MoveToForeground)
+
+ | | (SyncIsOn)
+ | (SyncIsOff)
+ | | (ScreenIsOn)
+ | (ScreenIsOff)
+ */
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(std::move(crashEvent1));
+ events.push_back(std::move(crashEvent2));
+ events.push_back(std::move(crashEvent3));
+ events.push_back(std::move(crashEvent4));
+ events.push_back(std::move(crashEvent5));
+ events.push_back(std::move(crashEvent6));
+ events.push_back(std::move(crashEvent7));
+ events.push_back(std::move(crashEvent8));
+ events.push_back(std::move(crashEvent9));
+ events.push_back(std::move(crashEvent10));
+ events.push_back(std::move(screenTurnedOnEvent));
+ events.push_back(std::move(screenTurnedOffEvent));
+ events.push_back(std::move(screenTurnedOnEvent2));
+ events.push_back(std::move(syncOnEvent1));
+ events.push_back(std::move(syncOffEvent1));
+ events.push_back(std::move(syncOnEvent2));
+ events.push_back(std::move(moveToBackgroundEvent1));
+ events.push_back(std::move(moveToForegroundEvent1));
+ events.push_back(std::move(moveToBackgroundEvent2));
+ events.push_back(std::move(moveToForegroundEvent2));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ // Validate dimension value.
+ EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ // Uid field.
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 9ec831b..b975907 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -113,96 +113,107 @@
}
} // anonymous namespace
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
-// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-// SendConfig(service, MakeConfig());
-// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
-// // initialized with.
-//
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
-//
-// ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
-// // Expect no metrics since the bucket has not finished yet.
-// EXPECT_EQ(1, report.metrics_size());
-// EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
-//}
-//
-//TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
-// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-// SendConfig(service, MakeConfig());
-// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
-// // initialized with.
-//
-// // Force the uidmap to update at timestamp 2.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-// // This is a new installation, so there shouldn't be a split (should be same as the without
-// // split case).
-// service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
-// String16(""));
-// // Goes into the second bucket.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
-//
-// ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-// EXPECT_EQ(1, report.metrics_size());
-// EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
-//}
-//
-//TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
-// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-// SendConfig(service, MakeConfig());
-// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
-// // initialized with.
-// service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
-// {String16("")});
-//
-// // Force the uidmap to update at timestamp 2.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-// service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
-// String16(""));
-// // Goes into the second bucket.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
-//
-// ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-// backfillStartEndTimestamp(&report);
-//
-// ASSERT_EQ(1, report.metrics_size());
-// ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
-// ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
-// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-// has_start_bucket_elapsed_nanos());
-// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-// has_end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
-//}
-//
-//TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
-// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-// SendConfig(service, MakeConfig());
-// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
-// // initialized with.
-// service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
-// {String16("")});
-//
-// // Force the uidmap to update at timestamp 2.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-// service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
-// // Goes into the second bucket.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
-//
-// ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-// backfillStartEndTimestamp(&report);
-//
-// ASSERT_EQ(1, report.metrics_size());
-// ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
-// ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
-// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-// has_start_bucket_elapsed_nanos());
-// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-// has_end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
-//}
+TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ SendConfig(service, MakeConfig());
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 2, 100).get());
+
+ ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
+ // Expect no metrics since the bucket has not finished yet.
+ EXPECT_EQ(1, report.metrics_size());
+ EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ SendConfig(service, MakeConfig());
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+
+ // Force the uidmap to update at timestamp 2.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+ // This is a new installation, so there shouldn't be a split (should be same as the without
+ // split case).
+ service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
+ String16(""));
+ // Goes into the second bucket.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
+
+ ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
+ EXPECT_EQ(1, report.metrics_size());
+ EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ SendConfig(service, MakeConfig());
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+ service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
+ {String16("")});
+
+ // Force the uidmap to update at timestamp 2.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+ service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
+ String16(""));
+ // Goes into the second bucket.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
+
+ ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
+ backfillStartEndTimestamp(&report);
+
+ ASSERT_EQ(1, report.metrics_size());
+ ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
+ ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
+ EXPECT_TRUE(report.metrics(0)
+ .count_metrics()
+ .data(0)
+ .bucket_info(0)
+ .has_start_bucket_elapsed_nanos());
+ EXPECT_TRUE(report.metrics(0)
+ .count_metrics()
+ .data(0)
+ .bucket_info(0)
+ .has_end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ SendConfig(service, MakeConfig());
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+ service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
+ {String16("")});
+
+ // Force the uidmap to update at timestamp 2.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+ service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
+ // Goes into the second bucket.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
+
+ ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
+ backfillStartEndTimestamp(&report);
+
+ ASSERT_EQ(1, report.metrics_size());
+ ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
+ ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
+ EXPECT_TRUE(report.metrics(0)
+ .count_metrics()
+ .data(0)
+ .bucket_info(0)
+ .has_start_bucket_elapsed_nanos());
+ EXPECT_TRUE(report.metrics(0)
+ .count_metrics()
+ .data(0)
+ .bucket_info(0)
+ .has_end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index 99dbaf1..a87bb71 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -64,317 +64,313 @@
} // namespace
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(ValueMetricE2eTest, TestPulledEvents) {
-// auto config = CreateStatsdConfig();
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// android::util::SUBSYSTEM_SLEEP_STATE);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// // When creating the config, the value metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& expectedPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-//
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 65);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 75);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// // Pulling alarm arrives on time and reset the sequential pulling alarm.
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 2 * bucketSizeNs + 15);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 4 * bucketSizeNs + 11);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::ValueMetricDataWrapper valueMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-// EXPECT_GT((int)valueMetrics.data_size(), 1);
-//
-// auto data = valueMetrics.data(0);
-// EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// // We have 4 buckets, the first one was incomplete since the condition was unknown.
-// EXPECT_EQ(4, data.bucket_info_size());
-//
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(0).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(1).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(2).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(3).values_size());
-//}
-//
-//TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
-// auto config = CreateStatsdConfig();
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// // 10 mins == 2 bucket durations.
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// android::util::SUBSYSTEM_SLEEP_STATE);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// // When creating the config, the value metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& expectedPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-//
-// // Screen off/on/off events.
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 65);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 75);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the
-// // future, data will be skipped.
-// processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
-//
-// // This screen state change will start a new bucket.
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 4 * bucketSizeNs + 65);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// // The alarm is delayed but we already created a bucket thanks to the screen state condition.
-// // This bucket does not have to be skipped since the alarm arrives in time for the next bucket.
-// processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 6 * bucketSizeNs + 31);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::ValueMetricDataWrapper valueMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-// EXPECT_GT((int)valueMetrics.data_size(), 1);
-//
-// auto data = valueMetrics.data(0);
-// EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(3, data.bucket_info_size());
-//
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(0).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(1).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(2).values_size());
-//}
-//
-//TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
-// auto config = CreateStatsdConfig(false);
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-//
-// auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
-// *config.add_atom_matcher() = batterySaverStartMatcher;
-// const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
-// auto metric_activation = config.add_metric_activation();
-// metric_activation->set_metric_id(metricId);
-// metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-// auto event_activation = metric_activation->add_event_activation();
-// event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
-// event_activation->set_ttl_seconds(ttlNs / 1000000000);
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// android::util::SUBSYSTEM_SLEEP_STATE);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // When creating the config, the value metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& expectedPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-//
-// // Pulling alarm arrives on time and reset the sequential pulling alarm.
-// processor->informPullAlarmFired(expectedPullTimeNs + 1); // 15 mins + 1 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // Activate the metric. A pull occurs here
-// const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
-// auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
-// processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1); // 20 mins + 1 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 2); // 25 mins + 2 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
-//
-// // Create random event to deactivate metric.
-// auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1);
-// processor->OnLogEvent(deactivationEvent.get());
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 3);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 4);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::ValueMetricDataWrapper valueMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-// EXPECT_GT((int)valueMetrics.data_size(), 0);
-//
-// auto data = valueMetrics.data(0);
-// EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// // We have 2 full buckets, the two surrounding the activation are dropped.
-// EXPECT_EQ(2, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, bucketInfo.values_size());
-//
-// bucketInfo = data.bucket_info(1);
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, bucketInfo.values_size());
-//}
+TEST(ValueMetricE2eTest, TestPulledEvents) {
+ auto config = CreateStatsdConfig();
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(),
+ android::util::SUBSYSTEM_SLEEP_STATE);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ // When creating the config, the value metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& expectedPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ auto screenOnEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 2 * bucketSizeNs + 15,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 11,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+ EXPECT_GT((int)valueMetrics.data_size(), 1);
+
+ auto data = valueMetrics.data(0);
+ EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ // We have 4 buckets, the first one was incomplete since the condition was unknown.
+ EXPECT_EQ(4, data.bucket_info_size());
+
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(0).values_size());
+
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(1).values_size());
+
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(2).values_size());
+
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(3).values_size());
+}
+
+TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
+ auto config = CreateStatsdConfig();
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ // 10 mins == 2 bucket durations.
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(),
+ android::util::SUBSYSTEM_SLEEP_STATE);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ // When creating the config, the value metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& expectedPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+ // Screen off/on/off events.
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ auto screenOnEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the
+ // future, data will be skipped.
+ processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
+
+ // This screen state change will start a new bucket.
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 65,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ // The alarm is delayed but we already created a bucket thanks to the screen state condition.
+ // This bucket does not have to be skipped since the alarm arrives in time for the next bucket.
+ processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 6 * bucketSizeNs + 31,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+ EXPECT_GT((int)valueMetrics.data_size(), 1);
+
+ auto data = valueMetrics.data(0);
+ EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(3, data.bucket_info_size());
+
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(0).values_size());
+
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(1).values_size());
+
+ EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(2).values_size());
+}
+
+TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
+ auto config = CreateStatsdConfig(false);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+ auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
+ *config.add_atom_matcher() = batterySaverStartMatcher;
+ const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
+ auto metric_activation = config.add_metric_activation();
+ metric_activation->set_metric_id(metricId);
+ metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
+ auto event_activation = metric_activation->add_event_activation();
+ event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
+ event_activation->set_ttl_seconds(ttlNs / 1000000000);
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(),
+ android::util::SUBSYSTEM_SLEEP_STATE);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // When creating the config, the value metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& expectedPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(expectedPullTimeNs + 1); // 15 mins + 1 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // Activate the metric. A pull occurs here
+ const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
+ auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
+ processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1); // 20 mins + 1 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 2); // 25 mins + 2 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
+
+ // Create random event to deactivate metric.
+ auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50);
+ processor->OnLogEvent(deactivationEvent.get());
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 3);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 4);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+ EXPECT_GT((int)valueMetrics.data_size(), 0);
+
+ auto data = valueMetrics.data(0);
+ EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ // We have 2 full buckets, the two surrounding the activation are dropped.
+ EXPECT_EQ(2, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, bucketInfo.values_size());
+
+ bucketInfo = data.bucket_info(1);
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, bucketInfo.values_size());
+}
/**
* Test initialization of a simple value metric that is sliced by a state.
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 21092e2..ddd8f95 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -61,292 +61,290 @@
return config;
}
-std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
- CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
+std::vector<int> attributionUids1 = {111, 222, 222};
+std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
-std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"),
- CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
+std::vector<int> attributionUids2 = {111, 222, 222};
+std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
-// TODO(b/149590301): Update this helper to use new socket schema.
-///*
-//Events:
-//Screen off is met from (200ns,1 min+500ns].
-//Acquire event for wl1 from 2ns to 1min+2ns
-//Acquire event for wl2 from 1min-10ns to 2min-15ns
-//*/
-//void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) {
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//
-// auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1);
-// auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200);
-// auto screenTurnedOnEvent2 =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + bucketSizeNs + 500);
-//
-// auto acquireEvent1 = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-// auto releaseEvent1 =
-// CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
-// auto acquireEvent2 =
-// CreateAcquireWakelockEvent(attributions2, "wl2", bucketStartTimeNs + bucketSizeNs - 10);
-// auto releaseEvent2 = CreateReleaseWakelockEvent(attributions2, "wl2",
-// bucketStartTimeNs + 2 * bucketSizeNs - 15);
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-//
-// events.push_back(std::move(screenTurnedOnEvent));
-// events.push_back(std::move(screenTurnedOffEvent));
-// events.push_back(std::move(screenTurnedOnEvent2));
-// events.push_back(std::move(acquireEvent1));
-// events.push_back(std::move(acquireEvent2));
-// events.push_back(std::move(releaseEvent1));
-// events.push_back(std::move(releaseEvent2));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//}
+/*
+Events:
+Screen off is met from (200ns,1 min+500ns].
+Acquire event for wl1 from 2ns to 1min+2ns
+Acquire event for wl2 from 1min-10ns to 2min-15ns
+*/
+void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+ auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ auto screenTurnedOnEvent2 =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 500,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+ auto acquireEvent1 = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ auto releaseEvent1 = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2,
+ attributionUids1, attributionTags1, "wl1");
+ auto acquireEvent2 = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 10,
+ attributionUids2, attributionTags2, "wl2");
+ auto releaseEvent2 = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 15,
+ attributionUids2, attributionTags2, "wl2");
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(std::move(screenTurnedOnEvent));
+ events.push_back(std::move(screenTurnedOffEvent));
+ events.push_back(std::move(screenTurnedOnEvent2));
+ events.push_back(std::move(acquireEvent1));
+ events.push_back(std::move(acquireEvent2));
+ events.push_back(std::move(releaseEvent1));
+ events.push_back(std::move(releaseEvent2));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+}
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::SUM);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// // Only 1 dimension output. The tag dimension in the predicate has been aggregated.
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-//
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // Validate bucket info.
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
-// data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // The wakelock holding interval starts from the screen off event and to the end of the 1st
-// // bucket.
-// EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::SUM);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-// // Dump the report after the end of 2nd bucket.
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // Two output buckets.
-// // The wakelock holding interval in the 1st bucket starts from the screen off event and to
-// // the end of the 1st bucket.
-// EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(),
-// bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200));
-// // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
-// // ends at the second screen on event.
-// EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
-//}
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::SUM);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 2 * bucketSizeNs + 90));
-// events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3",
-// bucketStartTimeNs + 2 * bucketSizeNs + 100));
-// events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3",
-// bucketStartTimeNs + 5 * bucketSizeNs + 100));
-// sortLogEventsByTimestamp(&events);
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // The last wakelock holding spans 4 buckets.
-// EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
-// EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
-// EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
-// EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-//
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(reports.reports_size(), 1);
-//
-// // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
-// // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
-// // itself.
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-// // Dump the report after the end of 2nd bucket. One dimension with one bucket.
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // The max is acquire event for wl1 to screen off start.
-// EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200);
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 2 * bucketSizeNs + 90));
-// events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3",
-// bucketStartTimeNs + 2 * bucketSizeNs + 100));
-// events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3",
-// bucketStartTimeNs + 5 * bucketSizeNs + 100));
-// sortLogEventsByTimestamp(&events);
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // The last wakelock holding spans 4 buckets.
-// EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
-// EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(),
-// bucketStartTimeNs + 5 * bucketSizeNs);
-// EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(),
-// bucketStartTimeNs + 6 * bucketSizeNs);
-//}
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::SUM);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ // Only 1 dimension output. The tag dimension in the predicate has been aggregated.
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // Validate bucket info.
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+ data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // The wakelock holding interval starts from the screen off event and to the end of the 1st
+ // bucket.
+ EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::SUM);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ // Dump the report after the end of 2nd bucket.
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // Two output buckets.
+ // The wakelock holding interval in the 1st bucket starts from the screen off event and to
+ // the end of the 1st bucket.
+ EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(),
+ bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200));
+ // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
+ // ends at the second screen on event.
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::SUM);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+ attributionUids1, attributionTags1, "wl3"));
+ events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100,
+ attributionUids1, attributionTags1, "wl3"));
+ sortLogEventsByTimestamp(&events);
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // The last wakelock holding spans 4 buckets.
+ EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
+ EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
+ EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
+ EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(reports.reports_size(), 1);
+
+ // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
+ // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
+ // itself.
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ // Dump the report after the end of 2nd bucket. One dimension with one bucket.
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // The max is acquire event for wl1 to screen off start.
+ EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+ attributionUids1, attributionTags1, "wl3"));
+ events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100,
+ attributionUids1, attributionTags1, "wl3"));
+ sortLogEventsByTimestamp(&events);
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // The last wakelock holding spans 4 buckets.
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 5 * bucketSizeNs);
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 6 * bucketSizeNs);
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp
index c0b4f43..e8200d5 100644
--- a/cmds/statsd/tests/external/StatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/StatsPuller_test.cpp
@@ -15,11 +15,14 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
+
#include <chrono>
#include <thread>
#include <vector>
+
#include "../metrics/metrics_test_helper.h"
#include "src/stats_log_util.h"
+#include "stats_event.h"
#include "tests/statsd_test_util.h"
#ifdef __ANDROID__
@@ -57,13 +60,22 @@
FakePuller puller;
-// TODO(b/149590301): Update this helper to use new socket schema.
-//shared_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) {
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(pullTagId, eventTimeNs);
-// event->write(value);
-// event->init();
-// return event;
-//}
+std::unique_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, pullTagId);
+ AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
+
+ AStatsEvent_writeInt64(statsEvent, value);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
class StatsPullerTest : public ::testing::Test {
public:
@@ -80,149 +92,148 @@
} // Anonymous namespace.
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST_F(StatsPullerTest, PullSuccess) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = true;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//
-// sleep_for(std::chrono::seconds(1));
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = true;
-//
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value);
-//}
-//
-//TEST_F(StatsPullerTest, PullFailAfterSuccess) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = true;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//
-// sleep_for(std::chrono::seconds(1));
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = false;
-// dataHolder.clear();
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//
-// pullSuccess = true;
-// dataHolder.clear();
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown
-//TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-// pullSuccess = true;
-// // timeout is 0.5
-// pullDelayNs = (long)(0.8 * NS_PER_SEC);
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = true;
-// dataHolder.clear();
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//TEST_F(StatsPullerTest, PullFail) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = false;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//TEST_F(StatsPullerTest, PullTakeTooLong) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = true;
-// pullDelayNs = NS_PER_SEC;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//TEST_F(StatsPullerTest, PullTooFast) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = true;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = true;
-//
-// dataHolder.clear();
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//}
-//
-//TEST_F(StatsPullerTest, PullFailsAndTooFast) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = false;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = true;
-//
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
+TEST_F(StatsPullerTest, PullSuccess) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ sleep_for(std::chrono::seconds(1));
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsPullerTest, PullFailAfterSuccess) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ sleep_for(std::chrono::seconds(1));
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = false;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+
+ pullSuccess = true;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown
+TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+ pullSuccess = true;
+ // timeout is 0.5
+ pullDelayNs = (long)(0.8 * NS_PER_SEC);
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullFail) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = false;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullTakeTooLong) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+ pullDelayNs = NS_PER_SEC;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullTooFast) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ dataHolder.clear();
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsPullerTest, PullFailsAndTooFast) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = false;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp
index 81590a2..f21954f2 100644
--- a/cmds/statsd/tests/external/puller_util_test.cpp
+++ b/cmds/statsd/tests/external/puller_util_test.cpp
@@ -13,12 +13,16 @@
// limitations under the License.
#include "external/puller_util.h"
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
+
#include <vector>
-#include "statslog.h"
+
#include "../metrics/metrics_test_helper.h"
+#include "stats_event.h"
+#include "statslog.h"
#ifdef __ANDROID__
@@ -58,212 +62,187 @@
ret.push_back(vec);
}
}
+
+std::shared_ptr<LogEvent> makeUidLogEvent(uint64_t timestampNs, int uid, int data1, int data2) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, uidAtomTagId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeInt32(statsEvent, data1);
+ AStatsEvent_writeInt32(statsEvent, data2);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::shared_ptr<LogEvent> makeNonUidAtomLogEvent(uint64_t timestampNs, int data1) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, nonUidAtomTagId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, data1);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
} // anonymous namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(puller_util, MergeNoDimension) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 30->22->31
-// event->write(isolatedUid);
-// event->write(hostNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->22->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(hostNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-// .WillRepeatedly(Return(hostUid));
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-// .WillRepeatedly(ReturnArg<0>());
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 22, 52};
-// EXPECT_EQ(1, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-//}
-//
-//TEST(puller_util, MergeWithDimension) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 30->32->31
-// event->write(isolatedUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->32->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->22->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(hostNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-// .WillRepeatedly(Return(hostUid));
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-// .WillRepeatedly(ReturnArg<0>());
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 22, 21};
-// vector<int> expectedV2 = {20, 32, 52};
-// EXPECT_EQ(2, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-// EXPECT_THAT(actual, Contains(expectedV2));
-//}
-//
-//TEST(puller_util, NoMergeHostUidOnly) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 20->32->31
-// event->write(hostUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->22->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(hostNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-// .WillRepeatedly(Return(hostUid));
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-// .WillRepeatedly(ReturnArg<0>());
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// // 20->32->31
-// // 20->22->21
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 32, 31};
-// vector<int> expectedV2 = {20, 22, 21};
-// EXPECT_EQ(2, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-// EXPECT_THAT(actual, Contains(expectedV2));
-//}
-//
-//TEST(puller_util, IsolatedUidOnly) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 30->32->31
-// event->write(hostUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 30->22->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(hostNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-// .WillRepeatedly(Return(hostUid));
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-// .WillRepeatedly(ReturnArg<0>());
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// // 20->32->31
-// // 20->22->21
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 32, 31};
-// vector<int> expectedV2 = {20, 22, 21};
-// EXPECT_EQ(2, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-// EXPECT_THAT(actual, Contains(expectedV2));
-//}
-//
-//TEST(puller_util, MultipleIsolatedUidToOneHostUid) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 30->32->31
-// event->write(isolatedUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 31->32->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(isolatedUid + 1);
-// event->write(isolatedNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->32->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid));
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 32, 73};
-// EXPECT_EQ(1, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-//}
-//
-//TEST(puller_util, NoNeedToMerge) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event =
-// make_shared<LogEvent>(nonUidAtomTagId, timestamp);
-// // 32
-// event->write(isolatedNonAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// event = make_shared<LogEvent>(nonUidAtomTagId, timestamp);
-// // 22
-// event->write(hostNonAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId, {} /*no additive fields*/);
-//
-// EXPECT_EQ(2, (int)inputData.size());
-//}
+TEST(puller_util, MergeNoDimension) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 30->22->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, isolatedUid, hostNonAdditiveData, isolatedAdditiveData));
+
+ // 20->22->21
+ inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 22, 52};
+ EXPECT_EQ(1, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, MergeWithDimension) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 30->32->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, isolatedUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+ // 20->32->21
+ inputData.push_back(
+ makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, hostAdditiveData));
+
+ // 20->22->21
+ inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 22, 21};
+ vector<int> expectedV2 = {20, 32, 52};
+ EXPECT_EQ(2, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+ EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, NoMergeHostUidOnly) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 20->32->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+ // 20->22->21
+ inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ // 20->32->31
+ // 20->22->21
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 32, 31};
+ vector<int> expectedV2 = {20, 22, 21};
+ EXPECT_EQ(2, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+ EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, IsolatedUidOnly) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 30->32->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+ // 30->22->21
+ inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ // 20->32->31
+ // 20->22->21
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 32, 31};
+ vector<int> expectedV2 = {20, 22, 21};
+ EXPECT_EQ(2, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+ EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, MultipleIsolatedUidToOneHostUid) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 30->32->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, isolatedUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+ // 31->32->21
+ inputData.push_back(
+ makeUidLogEvent(timestamp, isolatedUid + 1, isolatedNonAdditiveData, hostAdditiveData));
+
+ // 20->32->21
+ inputData.push_back(
+ makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid));
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 32, 73};
+ EXPECT_EQ(1, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, NoNeedToMerge) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 32
+ inputData.push_back(makeNonUidAtomLogEvent(timestamp, isolatedNonAdditiveData));
+
+ // 22
+ inputData.push_back(makeNonUidAtomLogEvent(timestamp, hostNonAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId, {} /*no additive fields*/);
+
+ EXPECT_EQ(2, (int)inputData.size());
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
index c4407f4..6dc041f 100644
--- a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
+++ b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
@@ -42,7 +42,7 @@
size_t size;
uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
- std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/-1, /*pid=*/-1);
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
logEvent->parseBuffer(buf, size);
AStatsEvent_release(statsEvent);
return logEvent;
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index b882678..d55996c 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -13,16 +13,19 @@
// limitations under the License.
#include "src/metrics/CountMetricProducer.h"
-#include "src/stats_log_util.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <math.h>
#include <stdio.h>
+
#include <vector>
+#include "metrics_test_helper.h"
+#include "src/stats_log_util.h"
+#include "stats_event.h"
+#include "tests/statsd_test_util.h"
+
using namespace testing;
using android::sp;
using std::set;
@@ -37,366 +40,392 @@
const ConfigKey kConfigKey(0, 12345);
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(CountMetricProducerTest, TestFirstBucket) {
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5,
-// 600 * NS_PER_SEC + NS_PER_SEC / 2);
-// EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
-// EXPECT_EQ(10, countProducer.mCurrentBucketNum);
-// EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
-//}
-//
-//TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-// int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-// int tagId = 1;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-//
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + 2);
-// event2.init();
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// // 2 events in bucket 1.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-//
-// // Flushes at event #2.
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// // Flushes.
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(2LL, buckets[0].mCount);
-//
-// // 1 matched event happens in bucket 2.
-// LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
-// event3.init();
-//
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
-// EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
-// EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
-// EXPECT_EQ(1LL, bucketInfo2.mCount);
-//
-// // nothing happens in bucket 3. we should not record anything for bucket 3.
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(2UL, buckets3.size());
-//}
-//
-//TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_condition(StringToId("SCREEN_ON"));
-//
-// LogEvent event1(1, bucketStartTimeNs + 1);
-// event1.init();
-//
-// LogEvent event2(1, bucketStartTimeNs + 10);
-// event2.init();
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs,
-// bucketStartTimeNs);
-//
-// countProducer.onConditionChanged(true, bucketStartTimeNs);
-// countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
-// // Upon this match event, the matched event1 is flushed.
-// countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// {
-// const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// const auto& bucketInfo = buckets[0];
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
-// EXPECT_EQ(1LL, bucketInfo.mCount);
-// }
-//}
-//
-//TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// int tagId = 1;
-// int conditionTagId = 2;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// 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);
-// event1.write("111"); // uid
-// event1.init();
-// ConditionKey key1;
-// key1[StringToId("APP_IN_BACKGROUND_PER_UID")] =
-// {getMockedDimensionKey(conditionTagId, 2, "111")};
-//
-// LogEvent event2(tagId, bucketStartTimeNs + 10);
-// event2.write("222"); // uid
-// 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));
-//
-// CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// const auto& bucketInfo = buckets[0];
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
-// EXPECT_EQ(1LL, bucketInfo.mCount);
-//}
-//
-//TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
-// sp<AlarmMonitor> alarmMonitor;
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-//
-// int tagId = 1;
-// int conditionTagId = 2;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// Alert alert;
-// alert.set_num_buckets(3);
-// alert.set_trigger_if_sum_gt(2);
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.write("111"); // uid
-// event1.init();
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
-// EXPECT_TRUE(anomalyTracker != nullptr);
-//
-// // Bucket is flushed yet.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// // App upgrade forces bucket flush.
-// // Check that there's a past bucket and the bucket end is not adjusted.
-// countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ((long long)bucketStartTimeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-// EXPECT_EQ((long long)eventUpgradeTimeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-// EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
-// // Anomaly tracker only contains full buckets.
-// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
-// // Next event occurs in same bucket as partial bucket created.
-// LogEvent event2(tagId, bucketStartTimeNs + 59 * NS_PER_SEC + 10);
-// event2.write("222"); // uid
-// event2.init();
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
-// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// // Third event in following bucket.
-// LogEvent event3(tagId, bucketStartTimeNs + 62 * NS_PER_SEC + 10);
-// event3.write("333"); // uid
-// event3.init();
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-// EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
-// EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//}
-//
-//TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-//
-// int tagId = 1;
-// int conditionTagId = 2;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.write("111"); // uid
-// event1.init();
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// // Bucket is flushed yet.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// // App upgrade forces bucket flush.
-// // Check that there's a past bucket and the bucket end is not adjusted.
-// countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ((int64_t)bucketStartTimeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-// EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
-//
-// // Next event occurs in same bucket as partial bucket created.
-// LogEvent event2(tagId, bucketStartTimeNs + 70 * NS_PER_SEC + 10);
-// event2.write("222"); // uid
-// event2.init();
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//
-// // Third event in following bucket.
-// LogEvent event3(tagId, bucketStartTimeNs + 121 * NS_PER_SEC + 10);
-// event3.write("333"); // uid
-// event3.init();
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-// EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ((int64_t)eventUpgradeTimeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
-//}
-//
-//TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
-// sp<AlarmMonitor> alarmMonitor;
-// Alert alert;
-// alert.set_id(11);
-// alert.set_metric_id(1);
-// alert.set_trigger_if_sum_gt(2);
-// alert.set_num_buckets(2);
-// const int32_t refPeriodSec = 1;
-// alert.set_refractory_period_secs(refPeriodSec);
-//
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-// int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
-//
-// int tagId = 1;
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + 2);
-// event2.init();
-// LogEvent event3(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// event3.init();
-// LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1);
-// event4.init();
-// LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2);
-// event5.init();
-// LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3);
-// event6.init();
-// LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
-// event7.init();
-//
-// // Two events in bucket #0.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-//
-// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-// EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-// // One event in bucket #2. No alarm as bucket #0 is trashed out.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-// EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-// // Two events in bucket #3.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
-// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-// EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
-// // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-// std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
-// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-// EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-// std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//}
+namespace {
+
+void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+}
+
+void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId, string uid) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeString(statsEvent, uid.c_str());
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+}
+
+} // namespace
+
+TEST(CountMetricProducerTest, TestFirstBucket) {
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5,
+ 600 * NS_PER_SEC + NS_PER_SEC / 2);
+ EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(10, countProducer.mCurrentBucketNum);
+ EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
+}
+
+TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+ int tagId = 1;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ // 2 events in bucket 1.
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // Flushes at event #2.
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ // Flushes.
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(2LL, buckets[0].mCount);
+
+ // 1 matched event happens in bucket 2.
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 2, tagId);
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
+ EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
+ EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo2.mCount);
+
+ // nothing happens in bucket 3. we should not record anything for bucket 3.
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(2UL, buckets3.size());
+}
+
+TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_condition(StringToId("SCREEN_ON"));
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs,
+ bucketStartTimeNs);
+
+ countProducer.onConditionChanged(true, bucketStartTimeNs);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, /*atomId=*/1);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
+
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
+
+ // Upon this match event, the matched event1 is flushed.
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 10, /*atomId=*/1);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ int tagId = 1;
+ int conditionTagId = 2;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ 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, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 10, tagId, /*uid=*/"222");
+
+ ConditionKey key1;
+ key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+ getMockedDimensionKey(conditionTagId, 2, "111")};
+
+ 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));
+
+ CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
+ sp<AlarmMonitor> alarmMonitor;
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+
+ int tagId = 1;
+ int conditionTagId = 2;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ Alert alert;
+ alert.set_num_buckets(3);
+ alert.set_trigger_if_sum_gt(2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
+ EXPECT_TRUE(anomalyTracker != nullptr);
+
+ // Bucket is flushed yet.
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+ EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+ // App upgrade forces bucket flush.
+ // Check that there's a past bucket and the bucket end is not adjusted.
+ countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ((long long)bucketStartTimeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+ EXPECT_EQ((long long)eventUpgradeTimeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
+ EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+ // Anomaly tracker only contains full buckets.
+ EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+ int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
+ // Next event occurs in same bucket as partial bucket created.
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 59 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+ // Third event in following bucket.
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + 62 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+
+ int tagId = 1;
+ int conditionTagId = 2;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ // Bucket is flushed yet.
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ // App upgrade forces bucket flush.
+ // Check that there's a past bucket and the bucket end is not adjusted.
+ countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ((int64_t)bucketStartTimeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
+ EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+
+ // Next event occurs in same bucket as partial bucket created.
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 70 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+
+ // Third event in following bucket.
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + 121 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ((int64_t)eventUpgradeTimeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
+}
+
+TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
+ sp<AlarmMonitor> alarmMonitor;
+ Alert alert;
+ alert.set_id(11);
+ alert.set_metric_id(1);
+ alert.set_trigger_if_sum_gt(2);
+ alert.set_num_buckets(2);
+ const int32_t refPeriodSec = 1;
+ alert.set_refractory_period_secs(refPeriodSec);
+
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + 2 * bucketSizeNs + 1, tagId);
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event4, bucketStartTimeNs + 3 * bucketSizeNs + 1, tagId);
+ LogEvent event5(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event5, bucketStartTimeNs + 3 * bucketSizeNs + 2, tagId);
+ LogEvent event6(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event6, bucketStartTimeNs + 3 * bucketSizeNs + 3, tagId);
+ LogEvent event7(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event7, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, tagId);
+
+ // Two events in bucket #0.
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+ // One event in bucket #2. No alarm as bucket #0 is trashed out.
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+ // Two events in bucket #3.
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
+ EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
+ // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+ std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
+ EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+ std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+}
TEST(CountMetricProducerTest, TestOneWeekTimeUnit) {
CountMetric metric;
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 6661374..6143dc0 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -13,17 +13,20 @@
// limitations under the License.
#include "src/metrics/DurationMetricProducer.h"
-#include "src/stats_log_util.h"
-#include "metrics_test_helper.h"
-#include "src/condition/ConditionWizard.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
+
#include <set>
#include <unordered_map>
#include <vector>
+#include "metrics_test_helper.h"
+#include "src/condition/ConditionWizard.h"
+#include "src/stats_log_util.h"
+#include "stats_event.h"
+
using namespace android::os::statsd;
using namespace testing;
using android::sp;
@@ -39,6 +42,22 @@
const ConfigKey kConfigKey(0, 12345);
+namespace {
+
+void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+}
+
+} // namespace
+
TEST(DurationMetricTrackerTest, TestFirstBucket) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
DurationMetric metric;
@@ -56,383 +75,386 @@
EXPECT_EQ(660000000005, durationProducer.getCurrentBucketEndTimeNs());
}
-// TODO(b/149590301): Update these to use new socket schema.
-//TEST(DurationMetricTrackerTest, TestNoCondition) {
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-// int tagId = 1;
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + bucketSizeNs + 2);
-// event2.init();
-//
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
-// EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// durationProducer.mPastBuckets.end());
-// const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(2UL, buckets.size());
-// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
-// EXPECT_EQ(2LL, buckets[1].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-// int tagId = 1;
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + 2);
-// event2.init();
-// LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
-// event3.init();
-// LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
-// event4.init();
-//
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-// durationProducer.mCondition = ConditionState::kFalse;
-//
-// EXPECT_FALSE(durationProducer.mCondition);
-// EXPECT_FALSE(durationProducer.isConditionSliced());
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
-// durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
-// EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// durationProducer.mPastBuckets.end());
-// const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets2.size());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
-// EXPECT_EQ(1LL, buckets2[0].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-// int tagId = 1;
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + 2);
-// event2.init();
-// LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
-// event3.init();
-// LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
-// event4.init();
-//
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
-// EXPECT_FALSE(durationProducer.isConditionSliced());
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
-// durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
-// const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets2.size());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
-// EXPECT_EQ(1LL, buckets2[0].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
-// /**
-// * The duration starts from the first bucket, through the two partial buckets (10-70sec),
-// * another bucket, and ends at the beginning of the next full bucket.
-// * Expected buckets:
-// * - [10,25]: 14 secs
-// * - [25,70]: All 45 secs
-// * - [70,130]: All 60 secs
-// * - [130, 210]: Only 5 secs (event ended at 135sec)
-// */
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
-// int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// std::vector<DurationBucket> buckets =
-// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration);
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-// buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(3UL, buckets.size());
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
-// EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
-// /**
-// * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
-// * - [10,70]: 59 secs
-// * - [70,75]: 5 sec
-// * - [75,130]: 55 secs
-// */
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
-// int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// std::vector<DurationBucket> buckets =
-// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs);
-// EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-// buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(3UL, buckets.size());
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
-// sp<AlarmMonitor> alarmMonitor;
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1;
-// int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// // Setup metric with alert.
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-// Alert alert;
-// alert.set_num_buckets(3);
-// alert.set_trigger_if_sum_gt(2);
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
-// EXPECT_TRUE(anomalyTracker != nullptr);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-//
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
-// anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//}
-//
-//TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1;
-// int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
-// LogEvent event1(tagId, startTimeNs);
-// event1.write("111"); // uid
-// event1.init();
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
-// std::vector<DurationBucket> buckets =
-// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1;
-// int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
-// LogEvent event1(tagId, startTimeNs);
-// event1.write("111"); // uid
-// event1.init();
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// // Stop occurs in the same partial bucket as created for the app upgrade.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// std::vector<DurationBucket> buckets =
-// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
-//}
+TEST(DurationMetricTrackerTest, TestNoCondition) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + bucketSizeNs + 2, tagId);
+
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ durationProducer.mPastBuckets.end());
+ const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(2UL, buckets.size());
+ EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
+ EXPECT_EQ(2LL, buckets[1].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
+
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ durationProducer.mCondition = ConditionState::kFalse;
+
+ EXPECT_FALSE(durationProducer.mCondition);
+ EXPECT_FALSE(durationProducer.isConditionSliced());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
+ durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ durationProducer.mPastBuckets.end());
+ const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets2.size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
+ EXPECT_EQ(1LL, buckets2[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
+
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
+ EXPECT_FALSE(durationProducer.isConditionSliced());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
+ durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets2.size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
+ EXPECT_EQ(1LL, buckets2[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
+ /**
+ * The duration starts from the first bucket, through the two partial buckets (10-70sec),
+ * another bucket, and ends at the beginning of the next full bucket.
+ * Expected buckets:
+ * - [10,25]: 14 secs
+ * - [25,70]: All 45 secs
+ * - [70,130]: All 60 secs
+ * - [130, 210]: Only 5 secs (event ended at 135sec)
+ */
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
+ int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ std::vector<DurationBucket> buckets =
+ durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration);
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(3UL, buckets.size());
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
+ EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
+ /**
+ * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
+ * - [10,70]: 59 secs
+ * - [70,75]: 5 sec
+ * - [75,130]: 55 secs
+ */
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
+ int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ std::vector<DurationBucket> buckets =
+ durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs);
+ EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(3UL, buckets.size());
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
+ sp<AlarmMonitor> alarmMonitor;
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1;
+ int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ // Setup metric with alert.
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+ Alert alert;
+ alert.set_num_buckets(3);
+ alert.set_trigger_if_sum_gt(2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
+ EXPECT_TRUE(anomalyTracker != nullptr);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+
+ // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
+ anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1;
+ int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ std::vector<DurationBucket> buckets =
+ durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1;
+ int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ // Stop occurs in the same partial bucket as created for the app upgrade.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ std::vector<DurationBucket> buckets =
+ durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index d416f13..e2eee03 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -410,40 +410,75 @@
return dimensions;
}
-// TODO(b/149590301): Update these helpers to use new socket schema.
-//std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
-// const android::view::DisplayStateEnum state, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(android::util::SCREEN_STATE_CHANGED, timestampNs);
-// EXPECT_TRUE(event->write(state));
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(
-// android::util::BATTERY_SAVER_MODE_STATE_CHANGED, timestampNs);
-// EXPECT_TRUE(event->write(BatterySaverModeStateChanged::ON));
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(
-// android::util::BATTERY_SAVER_MODE_STATE_CHANGED, timestampNs);
-// EXPECT_TRUE(event->write(BatterySaverModeStateChanged::OFF));
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
-// int level, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(android::util::SCREEN_BRIGHTNESS_CHANGED, timestampNs);
-// EXPECT_TRUE(event->write(level));
-// event->init();
-// return event;
-//
-//}
-//
+std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
+ uint64_t timestampNs, const android::view::DisplayStateEnum state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::ON);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::OFF);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_BRIGHTNESS_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, level);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
//std::unique_ptr<LogEvent> CreateScheduledJobStateChangedEvent(
// const std::vector<AttributionNodeInternal>& attributions, const string& jobName,
// const ScheduledJobStateChanged::State state, uint64_t timestampNs) {
@@ -470,121 +505,212 @@
// attributions, name, ScheduledJobStateChanged::FINISHED, timestampNs);
//}
//
-//std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(
-// const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-// const WakelockStateChanged::State state, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(android::util::WAKELOCK_STATE_CHANGED, timestampNs);
-// event->write(attributions);
-// event->write(android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
-// event->write(wakelockName);
-// event->write(state);
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
-// const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-// uint64_t timestampNs) {
-// return CreateWakelockStateChangedEvent(
-// attributions, wakelockName, WakelockStateChanged::ACQUIRE, timestampNs);
-//}
-//
-//std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
-// const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
-// uint64_t timestampNs) {
-// return CreateWakelockStateChangedEvent(
-// attributions, wakelockName, WakelockStateChanged::RELEASE, timestampNs);
-//}
-//
-//std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
-// const int uid, const ActivityForegroundStateChanged::State state, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(
-// android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, timestampNs);
-// event->write(uid);
-// event->write("pkg_name");
-// event->write("class_name");
-// event->write(state);
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs) {
-// return CreateActivityForegroundStateChangedEvent(
-// uid, ActivityForegroundStateChanged::BACKGROUND, timestampNs);
-//}
-//
-//std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs) {
-// return CreateActivityForegroundStateChangedEvent(
-// uid, ActivityForegroundStateChanged::FOREGROUND, timestampNs);
-//}
-//
-//std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(
-// const std::vector<AttributionNodeInternal>& attributions, const string& name,
-// const SyncStateChanged::State state, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(android::util::SYNC_STATE_CHANGED, timestampNs);
-// event->write(attributions);
-// event->write(name);
-// event->write(state);
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateSyncStartEvent(
-// const std::vector<AttributionNodeInternal>& attributions, const string& name,
-// uint64_t timestampNs) {
-// return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::ON, timestampNs);
-//}
-//
-//std::unique_ptr<LogEvent> CreateSyncEndEvent(
-// const std::vector<AttributionNodeInternal>& attributions, const string& name,
-// uint64_t timestampNs) {
-// return CreateSyncStateChangedEvent(attributions, name, SyncStateChanged::OFF, timestampNs);
-//}
-//
-//std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent(
-// const int uid, const ProcessLifeCycleStateChanged::State state, uint64_t timestampNs) {
-// auto logEvent = std::make_unique<LogEvent>(
-// android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, timestampNs);
-// logEvent->write(uid);
-// logEvent->write("");
-// logEvent->write(state);
-// logEvent->init();
-// return logEvent;
-//}
-//
-//std::unique_ptr<LogEvent> CreateAppCrashEvent(const int uid, uint64_t timestampNs) {
-// return CreateProcessLifeCycleStateChangedEvent(
-// uid, ProcessLifeCycleStateChanged::CRASHED, timestampNs);
-//}
-//
-//std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(android::util::APP_CRASH_OCCURRED, timestampNs);
-// event->write(uid);
-// event->write("eventType");
-// event->write("processName");
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
-// int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs) {
-// auto logEvent = std::make_unique<LogEvent>(
-// android::util::ISOLATED_UID_CHANGED, timestampNs);
-// logEvent->write(hostUid);
-// logEvent->write(isolatedUid);
-// logEvent->write(is_create);
-// logEvent->init();
-// return logEvent;
-//}
-//
-//std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
-// int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, timestampNs);
-// event->write(uid);
-// event->write(state);
-// event->init();
-// return event;
-//}
+std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& wakelockName,
+ const WakelockStateChanged::State state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::WAKELOCK_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeInt32(statsEvent, android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
+ AStatsEvent_writeString(statsEvent, wakelockName.c_str());
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& wakelockName) {
+ return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags,
+ wakelockName, WakelockStateChanged::ACQUIRE);
+}
+
+std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& wakelockName) {
+ return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags,
+ wakelockName, WakelockStateChanged::RELEASE);
+}
+
+std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
+ uint64_t timestampNs, const int uid, const ActivityForegroundStateChanged::State state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, "pkg_name");
+ AStatsEvent_writeString(statsEvent, "class_name");
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid) {
+ return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
+ ActivityForegroundStateChanged::BACKGROUND);
+}
+
+std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid) {
+ return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
+ ActivityForegroundStateChanged::FOREGROUND);
+}
+
+std::unique_ptr<LogEvent> CreateSyncStateChangedEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& name,
+ const SyncStateChanged::State state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::SYNC_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ vector<const char*> cTags(attributionTags.size());
+ for (int i = 0; i < cTags.size(); i++) {
+ cTags[i] = attributionTags[i].c_str();
+ }
+
+ AStatsEvent_writeAttributionChain(statsEvent,
+ reinterpret_cast<const uint32_t*>(attributionUids.data()),
+ cTags.data(), attributionUids.size());
+ AStatsEvent_writeString(statsEvent, name.c_str());
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& name) {
+ return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
+ SyncStateChanged::ON);
+}
+
+std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& name) {
+ return CreateSyncStateChangedEvent(timestampNs, attributionUids, attributionTags, name,
+ SyncStateChanged::OFF);
+}
+
+std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent(
+ uint64_t timestampNs, const int uid, const ProcessLifeCycleStateChanged::State state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, "");
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateAppCrashEvent(uint64_t timestampNs, const int uid) {
+ return CreateProcessLifeCycleStateChangedEvent(timestampNs, uid,
+ ProcessLifeCycleStateChanged::CRASHED);
+}
+
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::APP_CRASH_OCCURRED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, "eventType");
+ AStatsEvent_writeString(statsEvent, "processName");
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int hostUid,
+ int isolatedUid, bool is_create) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::ISOLATED_UID_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, hostUid);
+ AStatsEvent_writeInt32(statsEvent, isolatedUid);
+ AStatsEvent_writeInt32(statsEvent, is_create);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
+ uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::UID_PROCESS_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeInt32(statsEvent, state);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
const StatsdConfig& config, const ConfigKey& key,
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index c8326ee..4371015 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -166,11 +166,10 @@
// Create log event for screen state changed.
std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
- const android::view::DisplayStateEnum state, uint64_t timestampNs);
+ uint64_t timestampNs, const android::view::DisplayStateEnum state);
// Create log event for screen brightness state changed.
-std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
- int level, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level);
// Create log event when scheduled job starts.
std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
@@ -188,45 +187,42 @@
std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs);
// Create log event for app moving to background.
-std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid);
// Create log event for app moving to foreground.
-std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid);
// Create log event when the app sync starts.
-std::unique_ptr<LogEvent> CreateSyncStartEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& name,
- uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs, const vector<int>& uids,
+ const vector<string>& tags, const string& name);
// Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateSyncEndEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& name,
- uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateSyncEndEvent(uint64_t timestampNs, const vector<int>& uids,
+ const vector<string>& tags, const string& name);
// Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateAppCrashEvent(
- const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateAppCrashEvent(uint64_t timestampNs, const int uid);
// Create log event for an app crash.
-std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid);
// Create log event for acquiring wakelock.
-std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
- uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(uint64_t timestampNs, const vector<int>& uids,
+ const vector<string>& tags,
+ const string& wakelockName);
// Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
- uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs, const vector<int>& uids,
+ const vector<string>& tags,
+ const string& wakelockName);
// Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
- int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int hostUid,
+ int isolatedUid, bool is_create);
// Create log event for uid process state change.
std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
- int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs);
+ uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state);
// Helper function to create an AttributionNodeInternal proto.
AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 3a3eea9..e7036bb 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -48,6 +48,7 @@
import android.util.SparseArray;
import android.view.Display;
import android.view.KeyEvent;
+import android.view.SurfaceControl;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
@@ -1937,8 +1938,8 @@
* to declare the capability to take screenshot by setting the
* {@link android.R.styleable#AccessibilityService_canTakeScreenshot}
* property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
- * Besides, This API is only supported for default display now
- * {@link Display#DEFAULT_DISPLAY}.
+ * This API only will support {@link Display#DEFAULT_DISPLAY} until {@link SurfaceControl}
+ * supports non-default displays.
* </p>
*
* @param displayId The logic display id, must be {@link Display#DEFAULT_DISPLAY} for
@@ -1948,11 +1949,17 @@
*
* @return {@code true} if the taking screenshot accepted, {@code false} if too little time
* has elapsed since the last screenshot, invalid display or internal errors.
+ * @throws IllegalArgumentException if displayId is not {@link Display#DEFAULT_DISPLAY}.
*/
public boolean takeScreenshot(int displayId, @NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<ScreenshotResult> callback) {
Preconditions.checkNotNull(executor, "executor cannot be null");
Preconditions.checkNotNull(callback, "callback cannot be null");
+
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("DisplayId isn't the default display");
+ }
+
final IAccessibilityServiceConnection connection =
AccessibilityInteractionClient.getInstance().getConnection(
mConnectionId);
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index e2ecf85..9925d69 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -27,6 +27,7 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.usage.UsageStatsManager;
+import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
@@ -162,7 +163,7 @@
* might also make sense inside of a single app if the access is forwarded between two features of
* the app.
*
- * <p>An app can register an {@link AppOpsCollector} to get informed about what accesses the
+ * <p>An app can register an {@link OnOpNotedCallback} to get informed about what accesses the
* system is tracking for it. As each runtime permission has an associated app-op this API is
* particularly useful for an app that want to find unexpected private data accesses.
*/
@@ -206,16 +207,16 @@
private static final Object sLock = new Object();
- /** Current {@link AppOpsCollector}. Change via {@link #setNotedAppOpsCollector} */
+ /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */
@GuardedBy("sLock")
- private static @Nullable AppOpsCollector sNotedAppOpsCollector;
+ private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
/**
* Additional collector that collect accesses and forwards a few of them them via
* {@link IAppOpsService#reportRuntimeAppOpAccessMessageAndGetConfig}.
*/
- private static AppOpsCollector sMessageCollector =
- new AppOpsCollector() {
+ private static OnOpNotedCallback sMessageCollector =
+ new OnOpNotedCallback() {
@Override
public void onNoted(@NonNull SyncNotedAppOp op) {
reportStackTraceIfNeeded(op);
@@ -385,6 +386,13 @@
*/
public static final int WATCH_FOREGROUND_CHANGES = 1 << 0;
+ /**
+ * Flag for {@link #startWatchingMode} that causes the callback to happen on the switch-op
+ * instead the op the callback was registered. (This simulates pre-R behavior).
+ *
+ * @hide
+ */
+ public static final int CALL_BACK_ON_SWITCHED_OP = 1 << 1;
/**
* Flag to determine whether we should log noteOp/startOp calls to make sure they
@@ -1988,108 +1996,108 @@
};
/**
- * This specifies whether each option should allow the system
- * (and system ui) to bypass the user restriction when active.
+ * In which cases should an app be allowed to bypass the {@link #setUserRestriction user
+ * restriction} for a certain app-op.
*/
- private static boolean[] sOpAllowSystemRestrictionBypass = new boolean[] {
- true, //COARSE_LOCATION
- true, //FINE_LOCATION
- false, //GPS
- false, //VIBRATE
- false, //READ_CONTACTS
- false, //WRITE_CONTACTS
- false, //READ_CALL_LOG
- false, //WRITE_CALL_LOG
- false, //READ_CALENDAR
- false, //WRITE_CALENDAR
- true, //WIFI_SCAN
- false, //POST_NOTIFICATION
- false, //NEIGHBORING_CELLS
- false, //CALL_PHONE
- false, //READ_SMS
- false, //WRITE_SMS
- false, //RECEIVE_SMS
- false, //RECEIVE_EMERGECY_SMS
- false, //RECEIVE_MMS
- false, //RECEIVE_WAP_PUSH
- false, //SEND_SMS
- false, //READ_ICC_SMS
- false, //WRITE_ICC_SMS
- false, //WRITE_SETTINGS
- true, //SYSTEM_ALERT_WINDOW
- false, //ACCESS_NOTIFICATIONS
- false, //CAMERA
- false, //RECORD_AUDIO
- false, //PLAY_AUDIO
- false, //READ_CLIPBOARD
- false, //WRITE_CLIPBOARD
- false, //TAKE_MEDIA_BUTTONS
- false, //TAKE_AUDIO_FOCUS
- false, //AUDIO_MASTER_VOLUME
- false, //AUDIO_VOICE_VOLUME
- false, //AUDIO_RING_VOLUME
- false, //AUDIO_MEDIA_VOLUME
- false, //AUDIO_ALARM_VOLUME
- false, //AUDIO_NOTIFICATION_VOLUME
- false, //AUDIO_BLUETOOTH_VOLUME
- false, //WAKE_LOCK
- false, //MONITOR_LOCATION
- false, //MONITOR_HIGH_POWER_LOCATION
- false, //GET_USAGE_STATS
- false, //MUTE_MICROPHONE
- true, //TOAST_WINDOW
- false, //PROJECT_MEDIA
- false, //ACTIVATE_VPN
- false, //WALLPAPER
- false, //ASSIST_STRUCTURE
- false, //ASSIST_SCREENSHOT
- false, //READ_PHONE_STATE
- false, //ADD_VOICEMAIL
- false, // USE_SIP
- false, // PROCESS_OUTGOING_CALLS
- false, // USE_FINGERPRINT
- false, // BODY_SENSORS
- false, // READ_CELL_BROADCASTS
- false, // MOCK_LOCATION
- false, // READ_EXTERNAL_STORAGE
- false, // WRITE_EXTERNAL_STORAGE
- false, // TURN_ON_SCREEN
- false, // GET_ACCOUNTS
- false, // RUN_IN_BACKGROUND
- false, // AUDIO_ACCESSIBILITY_VOLUME
- false, // READ_PHONE_NUMBERS
- false, // REQUEST_INSTALL_PACKAGES
- false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
- false, // INSTANT_APP_START_FOREGROUND
- false, // ANSWER_PHONE_CALLS
- false, // OP_RUN_ANY_IN_BACKGROUND
- false, // OP_CHANGE_WIFI_STATE
- false, // OP_REQUEST_DELETE_PACKAGES
- false, // OP_BIND_ACCESSIBILITY_SERVICE
- false, // ACCEPT_HANDOVER
- false, // MANAGE_IPSEC_HANDOVERS
- false, // START_FOREGROUND
- true, // BLUETOOTH_SCAN
- false, // USE_BIOMETRIC
- false, // ACTIVITY_RECOGNITION
- false, // SMS_FINANCIAL_TRANSACTIONS
- false, // READ_MEDIA_AUDIO
- false, // WRITE_MEDIA_AUDIO
- false, // READ_MEDIA_VIDEO
- false, // WRITE_MEDIA_VIDEO
- false, // READ_MEDIA_IMAGES
- false, // WRITE_MEDIA_IMAGES
- false, // LEGACY_STORAGE
- false, // ACCESS_ACCESSIBILITY
- false, // READ_DEVICE_IDENTIFIERS
- false, // ACCESS_MEDIA_LOCATION
- false, // QUERY_ALL_PACKAGES
- false, // MANAGE_EXTERNAL_STORAGE
- false, // INTERACT_ACROSS_PROFILES
- false, // ACTIVATE_PLATFORM_VPN
- false, // LOADER_USAGE_STATS
- false, // ACCESS_CALL_AUDIO
- false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
+ private static RestrictionBypass[] sOpAllowSystemRestrictionBypass = new RestrictionBypass[] {
+ new RestrictionBypass(true, false), //COARSE_LOCATION
+ new RestrictionBypass(true, false), //FINE_LOCATION
+ null, //GPS
+ null, //VIBRATE
+ null, //READ_CONTACTS
+ null, //WRITE_CONTACTS
+ null, //READ_CALL_LOG
+ null, //WRITE_CALL_LOG
+ null, //READ_CALENDAR
+ null, //WRITE_CALENDAR
+ new RestrictionBypass(true, false), //WIFI_SCAN
+ null, //POST_NOTIFICATION
+ null, //NEIGHBORING_CELLS
+ null, //CALL_PHONE
+ null, //READ_SMS
+ null, //WRITE_SMS
+ null, //RECEIVE_SMS
+ null, //RECEIVE_EMERGECY_SMS
+ null, //RECEIVE_MMS
+ null, //RECEIVE_WAP_PUSH
+ null, //SEND_SMS
+ null, //READ_ICC_SMS
+ null, //WRITE_ICC_SMS
+ null, //WRITE_SETTINGS
+ new RestrictionBypass(true, false), //SYSTEM_ALERT_WINDOW
+ null, //ACCESS_NOTIFICATIONS
+ null, //CAMERA
+ new RestrictionBypass(false, true), //RECORD_AUDIO
+ null, //PLAY_AUDIO
+ null, //READ_CLIPBOARD
+ null, //WRITE_CLIPBOARD
+ null, //TAKE_MEDIA_BUTTONS
+ null, //TAKE_AUDIO_FOCUS
+ null, //AUDIO_MASTER_VOLUME
+ null, //AUDIO_VOICE_VOLUME
+ null, //AUDIO_RING_VOLUME
+ null, //AUDIO_MEDIA_VOLUME
+ null, //AUDIO_ALARM_VOLUME
+ null, //AUDIO_NOTIFICATION_VOLUME
+ null, //AUDIO_BLUETOOTH_VOLUME
+ null, //WAKE_LOCK
+ null, //MONITOR_LOCATION
+ null, //MONITOR_HIGH_POWER_LOCATION
+ null, //GET_USAGE_STATS
+ null, //MUTE_MICROPHONE
+ new RestrictionBypass(true, false), //TOAST_WINDOW
+ null, //PROJECT_MEDIA
+ null, //ACTIVATE_VPN
+ null, //WALLPAPER
+ null, //ASSIST_STRUCTURE
+ null, //ASSIST_SCREENSHOT
+ null, //READ_PHONE_STATE
+ null, //ADD_VOICEMAIL
+ null, // USE_SIP
+ null, // PROCESS_OUTGOING_CALLS
+ null, // USE_FINGERPRINT
+ null, // BODY_SENSORS
+ null, // READ_CELL_BROADCASTS
+ null, // MOCK_LOCATION
+ null, // READ_EXTERNAL_STORAGE
+ null, // WRITE_EXTERNAL_STORAGE
+ null, // TURN_ON_SCREEN
+ null, // GET_ACCOUNTS
+ null, // RUN_IN_BACKGROUND
+ null, // AUDIO_ACCESSIBILITY_VOLUME
+ null, // READ_PHONE_NUMBERS
+ null, // REQUEST_INSTALL_PACKAGES
+ null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
+ null, // INSTANT_APP_START_FOREGROUND
+ null, // ANSWER_PHONE_CALLS
+ null, // OP_RUN_ANY_IN_BACKGROUND
+ null, // OP_CHANGE_WIFI_STATE
+ null, // OP_REQUEST_DELETE_PACKAGES
+ null, // OP_BIND_ACCESSIBILITY_SERVICE
+ null, // ACCEPT_HANDOVER
+ null, // MANAGE_IPSEC_HANDOVERS
+ null, // START_FOREGROUND
+ new RestrictionBypass(true, false), // BLUETOOTH_SCAN
+ null, // USE_BIOMETRIC
+ null, // ACTIVITY_RECOGNITION
+ null, // SMS_FINANCIAL_TRANSACTIONS
+ null, // READ_MEDIA_AUDIO
+ null, // WRITE_MEDIA_AUDIO
+ null, // READ_MEDIA_VIDEO
+ null, // WRITE_MEDIA_VIDEO
+ null, // READ_MEDIA_IMAGES
+ null, // WRITE_MEDIA_IMAGES
+ null, // LEGACY_STORAGE
+ null, // ACCESS_ACCESSIBILITY
+ null, // READ_DEVICE_IDENTIFIERS
+ null, // ACCESS_MEDIA_LOCATION
+ null, // QUERY_ALL_PACKAGES
+ null, // MANAGE_EXTERNAL_STORAGE
+ null, // INTERACT_ACROSS_PROFILES
+ null, // ACTIVATE_PLATFORM_VPN
+ null, // LOADER_USAGE_STATS
+ null, // ACCESS_CALL_AUDIO
+ null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
};
/**
@@ -2485,11 +2493,11 @@
}
/**
- * Retrieve whether the op allows the system (and system ui) to
- * bypass the user restriction.
+ * Retrieve whether the op allows to bypass the user restriction.
+ *
* @hide
*/
- public static boolean opAllowSystemBypassRestriction(int op) {
+ public static RestrictionBypass opAllowSystemBypassRestriction(int op) {
return sOpAllowSystemRestrictionBypass[op];
}
@@ -2536,6 +2544,29 @@
}
/**
+ * When to not enforce {@link #setUserRestriction restrictions}.
+ *
+ * @hide
+ */
+ public static class RestrictionBypass {
+ /** Does the app need to be privileged to bypass the restriction */
+ public boolean isPrivileged;
+
+ /**
+ * Does the app need to have the EXEMPT_FROM_AUDIO_RESTRICTIONS permission to bypass the
+ * restriction
+ */
+ public boolean isRecordAudioRestrictionExcept;
+
+ public RestrictionBypass(boolean isPrivileged, boolean isRecordAudioRestrictionExcept) {
+ this.isPrivileged = isPrivileged;
+ this.isRecordAudioRestrictionExcept = isRecordAudioRestrictionExcept;
+ }
+
+ public static RestrictionBypass UNRESTRICTED = new RestrictionBypass(true, true);
+ }
+
+ /**
* Class holding all of the operation information associated with an app.
* @hide
*/
@@ -6689,6 +6720,13 @@
};
mModeWatchers.put(callback, cb);
}
+
+ // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
+ if (!Compatibility.isChangeEnabled(
+ CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE)) {
+ flags |= CALL_BACK_ON_SWITCHED_OP;
+ }
+
try {
mService.startWatchingModeWithFlags(op, packageName, flags, cb);
} catch (RemoteException e) {
@@ -7800,8 +7838,8 @@
*/
private void collectNotedOpForSelf(int op, @Nullable String featureId) {
synchronized (sLock) {
- if (sNotedAppOpsCollector != null) {
- sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.onSelfNoted(new SyncNotedAppOp(op, featureId));
}
}
sMessageCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
@@ -7950,8 +7988,8 @@
synchronized (sLock) {
for (int code = notedAppOps.nextSetBit(0); code != -1;
code = notedAppOps.nextSetBit(code + 1)) {
- if (sNotedAppOpsCollector != null) {
- sNotedAppOpsCollector.onNoted(new SyncNotedAppOp(code, featureId));
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, featureId));
}
}
}
@@ -7964,33 +8002,45 @@
}
/**
- * Register a new {@link AppOpsCollector}.
+ * Set a new {@link OnOpNotedCallback}.
*
- * <p>There can only ever be one collector per process. If there currently is a collector
- * registered, it will be unregistered.
+ * <p>There can only ever be one collector per process. If there currently is another callback
+ * set, this will fail.
*
- * <p><b>Only appops related to dangerous permissions are collected.</b>
+ * @param asyncExecutor executor to execute {@link OnOpNotedCallback#onAsyncNoted} on, {@code
+ * null} to unset
+ * @param callback listener to set, {@code null} to unset
*
- * @param collector The collector to set or {@code null} to unregister.
+ * @throws IllegalStateException If another callback is already registered
*/
- public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
+ public void setOnOpNotedCallback(@Nullable @CallbackExecutor Executor asyncExecutor,
+ @Nullable OnOpNotedCallback callback) {
+ Preconditions.checkState((callback == null) == (asyncExecutor == null));
+
synchronized (sLock) {
- if (sNotedAppOpsCollector != null) {
+ if (callback == null) {
+ Preconditions.checkState(sOnOpNotedCallback != null,
+ "No callback is currently registered");
+
try {
mService.stopWatchingAsyncNoted(mContext.getPackageName(),
- sNotedAppOpsCollector.mAsyncCb);
+ sOnOpNotedCallback.mAsyncCb);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
- }
- sNotedAppOpsCollector = collector;
+ sOnOpNotedCallback = null;
+ } else {
+ Preconditions.checkState(sOnOpNotedCallback == null,
+ "Another callback is already registered");
- if (sNotedAppOpsCollector != null) {
+ callback.mAsyncExecutor = asyncExecutor;
+ sOnOpNotedCallback = callback;
+
List<AsyncNotedAppOp> missedAsyncOps = null;
try {
mService.startWatchingAsyncNoted(mContext.getPackageName(),
- sNotedAppOpsCollector.mAsyncCb);
+ sOnOpNotedCallback.mAsyncCb);
missedAsyncOps = mService.extractAsyncOps(mContext.getPackageName());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -8000,10 +8050,9 @@
int numMissedAsyncOps = missedAsyncOps.size();
for (int i = 0; i < numMissedAsyncOps; i++) {
final AsyncNotedAppOp asyncNotedAppOp = missedAsyncOps.get(i);
- if (sNotedAppOpsCollector != null) {
- sNotedAppOpsCollector.getAsyncNotedExecutor().execute(
- () -> sNotedAppOpsCollector.onAsyncNoted(
- asyncNotedAppOp));
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.getAsyncNotedExecutor().execute(
+ () -> sOnOpNotedCallback.onAsyncNoted(asyncNotedAppOp));
}
}
}
@@ -8011,27 +8060,50 @@
}
}
+ // TODO moltmann: Remove
/**
- * @return {@code true} iff the process currently is currently collecting noted appops.
+ * Will be removed before R ships, leave it just to not break apps immediately.
*
- * @see #setNotedAppOpsCollector(AppOpsCollector)
+ * @removed
*
* @hide
*/
- public static boolean isCollectingNotedAppOps() {
- return sNotedAppOpsCollector != null;
+ @SystemApi
+ @Deprecated
+ public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
+ synchronized (sLock) {
+ if (collector != null) {
+ if (isListeningForOpNoted()) {
+ setOnOpNotedCallback(null, null);
+ }
+ setOnOpNotedCallback(new HandlerExecutor(Handler.getMain()), collector);
+ } else if (sOnOpNotedCallback != null) {
+ setOnOpNotedCallback(null, null);
+ }
+ }
}
/**
- * Callback an app can {@link #setNotedAppOpsCollector register} to monitor the app-ops the
- * system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp}
- * one of the callback methods of this object is called.
+ * @return {@code true} iff the process currently is currently collecting noted appops.
*
- * <p><b>There will be a callback for all app-ops related to runtime permissions, but not
+ * @see #setOnOpNotedCallback
+ *
+ * @hide
+ */
+ public static boolean isListeningForOpNoted() {
+ return sOnOpNotedCallback != null;
+ }
+
+ /**
+ * Callback an app can {@link #setOnOpNotedCallback set} to monitor the app-ops the
+ * system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp}
+ * one of a method of this object is called.
+ *
+ * <p><b>There will be a call for all app-ops related to runtime permissions, but not
* necessarily for all other app-ops.
*
* <pre>
- * setNotedAppOpsCollector(new AppOpsCollector() {
+ * setOnOpNotedCallback(getMainExecutor(), new OnOpNotedCallback() {
* ArraySet<Pair<String, String>> opsNotedForThisProcess = new ArraySet<>();
*
* private synchronized void addAccess(String op, String accessLocation) {
@@ -8056,24 +8128,36 @@
* });
* </pre>
*
- * @see #setNotedAppOpsCollector
+ * @see #setOnOpNotedCallback
*/
- public abstract static class AppOpsCollector {
+ public abstract static class OnOpNotedCallback {
+ private @NonNull Executor mAsyncExecutor;
+
/** Callback registered with the system. This will receive the async notes ops */
private final IAppOpsAsyncNotedCallback mAsyncCb = new IAppOpsAsyncNotedCallback.Stub() {
@Override
public void opNoted(AsyncNotedAppOp op) {
Objects.requireNonNull(op);
- getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
+ long token = Binder.clearCallingIdentity();
+ try {
+ getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
};
+ // TODO moltmann: Remove
/**
+ * Will be removed before R ships.
+ *
* @return The executor for the system to use when calling {@link #onAsyncNoted}.
+ *
+ * @hide
*/
- public @NonNull Executor getAsyncNotedExecutor() {
- return new HandlerExecutor(Handler.getMain());
+ protected @NonNull Executor getAsyncNotedExecutor() {
+ return mAsyncExecutor;
}
/**
@@ -8083,7 +8167,7 @@
* <p>Called on the calling thread before the API returns. This allows the app to e.g.
* collect stack traces to figure out where the access came from.
*
- * @param op The op noted
+ * @param op op noted
*/
public abstract void onNoted(@NonNull SyncNotedAppOp op);
@@ -8093,7 +8177,7 @@
* <p>This is very similar to {@link #onNoted} only that the tracking was not caused by the
* API provider in a separate process, but by one in the app's own process.
*
- * @param op The op noted
+ * @param op op noted
*/
public abstract void onSelfNoted(@NonNull SyncNotedAppOp op);
@@ -8105,14 +8189,30 @@
* guaranteed. Due to how async calls work in Android this might even be delivered slightly
* before the private data is delivered to the app.
*
- * <p>If the app is not running or no {@link AppOpsCollector} is registered a small amount
- * of noted app-ops are buffered and then delivered as soon as a collector is registered.
+ * <p>If the app is not running or no {@link OnOpNotedCallback} is registered a small amount
+ * of noted app-ops are buffered and then delivered as soon as a listener is registered.
*
- * @param asyncOp The op noted
+ * @param asyncOp op noted
*/
public abstract void onAsyncNoted(@NonNull AsyncNotedAppOp asyncOp);
}
+ // TODO moltmann: Remove
+ /**
+ * Will be removed before R ships, leave it just to not break apps immediately.
+ *
+ * @removed
+ *
+ * @hide
+ */
+ @SystemApi
+ @Deprecated
+ public abstract static class AppOpsCollector extends OnOpNotedCallback {
+ public @NonNull Executor getAsyncNotedExecutor() {
+ return new HandlerExecutor(Handler.getMain());
+ }
+ };
+
/**
* Generate a stack trace used for noted app-ops logging.
*
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index c2b2063..4d955db 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,10 +28,11 @@
/**
* When an {@link AppOpsManager#noteOp(String, int, String, String, String) app-op is noted} and the
- * app the app-op is noted for has a {@link AppOpsManager.AppOpsCollector} registered the note-event
- * needs to be delivered to the collector. Usually this is done via an {@link SyncNotedAppOp}, but
- * in some cases this is not possible. In this case an {@link AsyncNotedAppOp} is send to the system
- * server and then forwarded to the {@link AppOpsManager.AppOpsCollector} in the app.
+ * app the app-op is noted for has a {@link AppOpsManager.OnOpNotedCallback} registered the
+ * note-event needs to be delivered to the callback. Usually this is done via an
+ * {@link SyncNotedAppOp}, but in some cases this is not possible. In this case an
+ * {@link AsyncNotedAppOp} is send to the system server and then forwarded to the
+ * {@link AppOpsManager.OnOpNotedCallback} in the app.
*/
@Immutable
@DataClass(genEqualsHashCode = true,
@@ -53,7 +55,7 @@
private final @NonNull String mMessage;
/** Milliseconds since epoch when the op was noted */
- private final @IntRange(from = 0) long mTime;
+ private final @CurrentTimeMillisLong long mTime;
/**
* @return Op that was noted.
@@ -70,7 +72,7 @@
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -104,7 +106,7 @@
@IntRange(from = 0) int notingUid,
@Nullable String featureId,
@NonNull String message,
- @IntRange(from = 0) long time) {
+ @CurrentTimeMillisLong long time) {
this.mOpCode = opCode;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOpCode,
@@ -119,8 +121,7 @@
NonNull.class, null, mMessage);
this.mTime = time;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, mTime,
- "from", 0);
+ CurrentTimeMillisLong.class, null, mTime);
onConstructed();
}
@@ -153,7 +154,7 @@
* Milliseconds since epoch when the op was noted
*/
@DataClass.Generated.Member
- public @IntRange(from = 0) long getTime() {
+ public @CurrentTimeMillisLong long getTime() {
return mTime;
}
@@ -240,8 +241,7 @@
NonNull.class, null, mMessage);
this.mTime = time;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, mTime,
- "from", 0);
+ CurrentTimeMillisLong.class, null, mTime);
onConstructed();
}
@@ -261,10 +261,10 @@
};
@DataClass.Generated(
- time = 1583375913345L,
- codegenVersion = "1.0.14",
+ time = 1583866178330L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.IntRange(from=0L) long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.IntRange(from=0L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.CurrentTimeMillisLong long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 28b28da..145d513 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -37,13 +37,15 @@
/**
* Called whenever IActivityManager.startActivity is called on an activity that is already
- * running in the pinned stack and the activity is not actually started, but the task is either
- * brought to the front or a new Intent is delivered to it.
+ * running, but the task is either brought to the front or a new Intent is delivered to it.
*
+ * @param task information about the task the activity was relaunched into
+ * @param homeVisible whether or not the home task is visible
* @param clearedTask whether or not the launch activity also cleared the task as a part of
* starting
*/
- void onPinnedActivityRestartAttempt(boolean clearedTask);
+ void onActivityRestartAttempt(in ActivityManager.RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask);
/**
* Called when we launched an activity that we forced to be resizable.
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 34684c4..4cb8d93 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -175,11 +175,4 @@
* Called from SystemUI when it shows the AoD UI.
*/
oneway void setInAmbientMode(boolean inAmbientMode, long animationDuration);
-
- /**
- * Called when the wallpaper needs to zoom out.
- * The zoom value goes from 0 to 1 (inclusive) where 1 means fully zoomed out,
- * 0 means fully zoomed in
- */
- oneway void setWallpaperZoomOut(float zoom, String callingPackage, int displayId);
}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 3f2ec44..94b237c 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -134,6 +134,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static final int USER_LOCKED_SOUND = 0x00000020;
/**
@@ -331,6 +332,7 @@
/**
* @hide
*/
+ @TestApi
public void lockFields(int field) {
mUserLockedFields |= field;
}
diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index aa11b95..13b90ca 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -28,9 +28,9 @@
* Description of an app-op that was noted for the current process.
*
* <p>This is either delivered after a
- * {@link AppOpsManager.AppOpsCollector#onNoted(SyncNotedAppOp) two way binder call} or
+ * {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or
* when the app
- * {@link AppOpsManager.AppOpsCollector#onSelfNoted(SyncNotedAppOp) notes an app-op for
+ * {@link AppOpsManager.OnOpNotedCallback#onSelfNoted(SyncNotedAppOp) notes an app-op for
* itself}.
*/
@Immutable
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index b892b8e..93772de 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -16,6 +16,7 @@
package android.app;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.TaskSnapshot;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -53,7 +54,8 @@
@Override
@UnsupportedAppUsage
- public void onPinnedActivityRestartAttempt(boolean clearedTask) throws RemoteException {
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) throws RemoteException {
}
@Override
@@ -68,14 +70,14 @@
}
@Override
- public void onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo taskInfo,
+ public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
int requestedDisplayId) throws RemoteException {
onActivityLaunchOnSecondaryDisplayFailed();
}
/**
* @deprecated see {@link
- * #onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo, int)}
+ * #onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo, int)}
*/
@Deprecated
@UnsupportedAppUsage
@@ -84,7 +86,7 @@
@Override
@UnsupportedAppUsage
- public void onActivityLaunchOnSecondaryDisplayRerouted(ActivityManager.RunningTaskInfo taskInfo,
+ public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
int requestedDisplayId) throws RemoteException {
}
@@ -98,13 +100,13 @@
}
@Override
- public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
+ public void onTaskMovedToFront(RunningTaskInfo taskInfo)
throws RemoteException {
onTaskMovedToFront(taskInfo.taskId);
}
/**
- * @deprecated see {@link #onTaskMovedToFront(ActivityManager.RunningTaskInfo)}
+ * @deprecated see {@link #onTaskMovedToFront(RunningTaskInfo)}
*/
@Deprecated
@UnsupportedAppUsage
@@ -112,26 +114,26 @@
}
@Override
- public void onTaskRemovalStarted(ActivityManager.RunningTaskInfo taskInfo)
+ public void onTaskRemovalStarted(RunningTaskInfo taskInfo)
throws RemoteException {
onTaskRemovalStarted(taskInfo.taskId);
}
/**
- * @deprecated see {@link #onTaskRemovalStarted(ActivityManager.RunningTaskInfo)}
+ * @deprecated see {@link #onTaskRemovalStarted(RunningTaskInfo)}
*/
@Deprecated
public void onTaskRemovalStarted(int taskId) throws RemoteException {
}
@Override
- public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo)
+ public void onTaskDescriptionChanged(RunningTaskInfo taskInfo)
throws RemoteException {
onTaskDescriptionChanged(taskInfo.taskId, taskInfo.taskDescription);
}
/**
- * @deprecated see {@link #onTaskDescriptionChanged(ActivityManager.RunningTaskInfo)}
+ * @deprecated see {@link #onTaskDescriptionChanged(RunningTaskInfo)}
*/
@Deprecated
public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
@@ -166,7 +168,7 @@
}
@Override
- public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo)
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo)
throws RemoteException {
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index d9405e1..345eaae 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1858,13 +1858,12 @@
*
* @hide
*/
- public void setWallpaperZoomOut(float zoom) {
+ public void setWallpaperZoomOut(IBinder windowToken, float zoom) {
if (zoom < 0 || zoom > 1f) {
throw new IllegalArgumentException("zoom must be between 0 and one: " + zoom);
}
try {
- sGlobals.mService.setWallpaperZoomOut(zoom, mContext.getOpPackageName(),
- mContext.getDisplayId());
+ WindowManagerGlobal.getWindowSession().setWallpaperZoomOut(windowToken, zoom);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index ccd8199..0d461f5 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -174,7 +174,7 @@
public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
/**
- * An intent extra that contains one appWidgetId.
+ * An intent extra (int) that contains one appWidgetId.
* <p>
* The value will be an int that can be retrieved like this:
* {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
@@ -182,7 +182,7 @@
public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
/**
- * A bundle extra that contains whether or not an app has finished restoring a widget.
+ * A bundle extra (boolean) that contains whether or not an app has finished restoring a widget.
* <p> After restore, the app should set OPTION_APPWIDGET_RESTORE_COMPLETED to true on its
* widgets followed by calling {@link #updateAppWidget} to update the views.
*
@@ -192,22 +192,26 @@
/**
- * A bundle extra that contains the lower bound on the current width, in dips, of a widget instance.
+ * A bundle extra (int) that contains the lower bound on the current width, in dips, of a
+ * widget instance.
*/
public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
/**
- * A bundle extra that contains the lower bound on the current height, in dips, of a widget instance.
+ * A bundle extra (int) that contains the lower bound on the current height, in dips, of a
+ * widget instance.
*/
public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
/**
- * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
+ * A bundle extra (int) that contains the upper bound on the current width, in dips, of a
+ * widget instance.
*/
public static final String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth";
/**
- * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
+ * A bundle extra (int) that contains the upper bound on the current width, in dips, of a
+ * widget instance.
*/
public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
diff --git a/core/java/android/companion/WifiDeviceFilter.java b/core/java/android/companion/WifiDeviceFilter.java
index 58bf874..8b48f4c 100644
--- a/core/java/android/companion/WifiDeviceFilter.java
+++ b/core/java/android/companion/WifiDeviceFilter.java
@@ -51,6 +51,7 @@
* expression will be shown
*/
@DataClass.ParcelWith(Parcelling.BuiltIn.ForPattern.class)
+ @DataClass.MaySetToNull
private @Nullable Pattern mNamePattern = null;
/**
@@ -86,7 +87,7 @@
- // Code below generated by codegen v1.0.11.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -273,7 +274,7 @@
* If set, only devices with BSSID matching the given one will be shown
*/
@DataClass.Generated.Member
- public @NonNull Builder setBssid(@Nullable MacAddress value) {
+ public @NonNull Builder setBssid(@NonNull MacAddress value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mBssid = value;
@@ -322,11 +323,15 @@
}
@DataClass.Generated(
- time = 1571960300742L,
- codegenVersion = "1.0.11",
+ time = 1582688421965L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/companion/WifiDeviceFilter.java",
- inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.Nullable java.util.regex.Pattern mNamePattern\nprivate @android.annotation.Nullable android.net.MacAddress mBssid\nprivate @android.annotation.NonNull android.net.MacAddress mBssidMask\npublic @java.lang.Override boolean matches(android.net.wifi.ScanResult)\npublic @java.lang.Override java.lang.String getDeviceDisplayName(android.net.wifi.ScanResult)\npublic @java.lang.Override int getMediumType()\nclass WifiDeviceFilter extends java.lang.Object implements [android.companion.DeviceFilter<android.net.wifi.ScanResult>]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=false, genBuilder=true, genEqualsHashCode=true, genHiddenGetters=true)")
+ inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @com.android.internal.util.DataClass.MaySetToNull @android.annotation.Nullable java.util.regex.Pattern mNamePattern\nprivate @android.annotation.Nullable android.net.MacAddress mBssid\nprivate @android.annotation.NonNull android.net.MacAddress mBssidMask\npublic @java.lang.Override boolean matches(android.net.wifi.ScanResult)\npublic @java.lang.Override java.lang.String getDeviceDisplayName(android.net.wifi.ScanResult)\npublic @java.lang.Override int getMediumType()\nclass WifiDeviceFilter extends java.lang.Object implements [android.companion.DeviceFilter<android.net.wifi.ScanResult>]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=false, genBuilder=true, genEqualsHashCode=true, genHiddenGetters=true)")
@Deprecated
private void __metadata() {}
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 911ffa0..31e1fc8 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -83,6 +83,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Random;
@@ -2670,6 +2671,15 @@
ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
}
+ /** @removed */
+ @Deprecated
+ public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+ @NotifyFlags int flags) {
+ final Collection<Uri> asCollection = new ArrayList<>();
+ uris.forEach(asCollection::add);
+ notifyChange(asCollection, observer, flags);
+ }
+
/**
* Notify registered observers that several rows have been updated.
* <p>
@@ -2694,7 +2704,7 @@
* @param flags Flags such as {@link #NOTIFY_SYNC_TO_NETWORK} or
* {@link #NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS}.
*/
- public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+ public void notifyChange(@NonNull Collection<Uri> uris, @Nullable ContentObserver observer,
@NotifyFlags int flags) {
Objects.requireNonNull(uris, "uris");
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6cba327..5e9ed60 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -71,6 +71,7 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams.WindowType;
import android.view.autofill.AutofillManager.AutofillClient;
import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
import android.view.textclassifier.TextClassificationManager;
@@ -5820,7 +5821,7 @@
* @see #WALLPAPER_SERVICE
* @throws IllegalArgumentException if token is invalid
*/
- public @NonNull Context createWindowContext(int type, @Nullable Bundle options) {
+ public @NonNull Context createWindowContext(@WindowType int type, @Nullable Bundle options) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 91d214b..b7e04cf 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -42,6 +42,7 @@
import android.os.UserHandle;
import android.view.Display;
import android.view.DisplayAdjustments;
+import android.view.WindowManager.LayoutParams.WindowType;
import android.view.autofill.AutofillManager.AutofillClient;
import java.io.File;
@@ -978,7 +979,7 @@
@Override
@NonNull
- public Context createWindowContext(int type, @Nullable Bundle options) {
+ public Context createWindowContext(@WindowType int type, @Nullable Bundle options) {
return mBase.createWindowContext(type, options);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c6f6972..38c1890 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -26,6 +26,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.AppGlobals;
@@ -86,6 +87,7 @@
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
+import java.util.TimeZone;
/**
* An intent is an abstract description of an operation to be performed. It
@@ -1881,6 +1883,20 @@
"android.intent.action.MANAGE_PERMISSIONS";
/**
+ * Activity action: Launch UI to manage auto-revoke state.
+ * <p>
+ * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose
+ * auto-revoke state will be reviewed (mandatory).
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_AUTO_REVOKE_PERMISSIONS =
+ "android.intent.action.AUTO_REVOKE_PERMISSIONS";
+
+ /**
* Activity action: Launch UI to review permissions for an app.
* The system uses this intent if permission review for apps not
* supporting the new runtime permissions model is enabled. In
@@ -2298,7 +2314,8 @@
/**
* Broadcast Action: The timezone has changed. The intent will have the following extra values:</p>
* <ul>
- * <li><em>time-zone</em> - The java.util.TimeZone.getID() value identifying the new time zone.</li>
+ * <li>{@link #EXTRA_TIMEZONE} - The java.util.TimeZone.getID() value identifying the new
+ * time zone.</li>
* </ul>
*
* <p class="note">This is a protected intent that can only be sent
@@ -5771,6 +5788,14 @@
public static final String EXTRA_TIME = "android.intent.extra.TIME";
/**
+ * Extra sent with {@link #ACTION_TIMEZONE_CHANGED} specifying the new time zone of the device.
+ *
+ * <p>Type: String, the same as returned by {@link TimeZone#getID()} to identify time zones.
+ */
+ @SuppressLint("ActionValue")
+ public static final String EXTRA_TIMEZONE = "time-zone";
+
+ /**
* Optional int extra for {@link #ACTION_TIME_CHANGED} that indicates the
* user has set their time format preference. See {@link #EXTRA_TIME_PREF_VALUE_USE_12_HOUR},
* {@link #EXTRA_TIME_PREF_VALUE_USE_24_HOUR} and
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 61128f2..f19ab01 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -274,6 +274,9 @@
*/
public static final String SCHEME_HTTPS = "https";
+ /** The value to indicate a wildcard for incoming match arguments. */
+ private static final String WILDCARD = "*";
+
private int mPriority;
@UnsupportedAppUsage
private int mOrder;
@@ -758,6 +761,17 @@
* @return True if the action is listed in the filter.
*/
public final boolean matchAction(String action) {
+ return matchAction(action, false);
+ }
+
+ /**
+ * Variant of {@link #matchAction(String)} that allows a wildcard for the provided action.
+ * @param wildcardSupported if true, will allow action to use wildcards
+ */
+ private boolean matchAction(String action, boolean wildcardSupported) {
+ if (wildcardSupported && !mActions.isEmpty() && WILDCARD.equals(action)) {
+ return true;
+ }
return hasAction(action);
}
@@ -1120,20 +1134,33 @@
* {@link IntentFilter#MATCH_CATEGORY_HOST}.
*/
public int match(Uri data) {
+ return match(data, false);
+ }
+
+ /**
+ * Variant of {@link #match(Uri)} that supports wildcards on the scheme, host and
+ * path of the provided {@link Uri}
+ *
+ * @param wildcardSupported if true, will allow parameters to use wildcards
+ * @hide
+ */
+ public int match(Uri data, boolean wildcardSupported) {
String host = data.getHost();
if (host == null) {
return NO_MATCH_DATA;
}
if (false) Log.v("IntentFilter",
"Match host " + host + ": " + mHost);
- if (mWild) {
- if (host.length() < mHost.length()) {
+ if (!wildcardSupported || !WILDCARD.equals(host)) {
+ if (mWild) {
+ if (host.length() < mHost.length()) {
+ return NO_MATCH_DATA;
+ }
+ host = host.substring(host.length() - mHost.length());
+ }
+ if (host.compareToIgnoreCase(mHost) != 0) {
return NO_MATCH_DATA;
}
- host = host.substring(host.length()-mHost.length());
- }
- if (host.compareToIgnoreCase(mHost) != 0) {
- return NO_MATCH_DATA;
}
if (mPort >= 0) {
if (mPort != data.getPort()) {
@@ -1207,9 +1234,21 @@
* filter.
*/
public final boolean hasDataSchemeSpecificPart(String data) {
+ return hasDataSchemeSpecificPart(data, false);
+ }
+
+ /**
+ * Variant of {@link #hasDataSchemeSpecificPart(String)} that supports wildcards on the provided
+ * ssp.
+ * @param supportWildcards if true, will allow parameters to use wildcards
+ */
+ private boolean hasDataSchemeSpecificPart(String data, boolean supportWildcards) {
if (mDataSchemeSpecificParts == null) {
return false;
}
+ if (supportWildcards && WILDCARD.equals(data) && mDataSchemeSpecificParts.size() > 0) {
+ return true;
+ }
final int numDataSchemeSpecificParts = mDataSchemeSpecificParts.size();
for (int i = 0; i < numDataSchemeSpecificParts; i++) {
final PatternMatcher pe = mDataSchemeSpecificParts.get(i);
@@ -1388,9 +1427,21 @@
* filter.
*/
public final boolean hasDataPath(String data) {
+ return hasDataPath(data, false);
+ }
+
+ /**
+ * Variant of {@link #hasDataPath(String)} that supports wildcards on the provided scheme, host,
+ * and path.
+ * @param wildcardSupported if true, will allow parameters to use wildcards
+ */
+ private boolean hasDataPath(String data, boolean wildcardSupported) {
if (mDataPaths == null) {
return false;
}
+ if (wildcardSupported && WILDCARD.equals(data)) {
+ return true;
+ }
final int numDataPaths = mDataPaths.size();
for (int i = 0; i < numDataPaths; i++) {
final PatternMatcher pe = mDataPaths.get(i);
@@ -1435,13 +1486,24 @@
* {@link #MATCH_CATEGORY_PORT}, {@link #NO_MATCH_DATA}.
*/
public final int matchDataAuthority(Uri data) {
- if (mDataAuthorities == null || data == null) {
+ return matchDataAuthority(data, false);
+ }
+
+ /**
+ * Variant of {@link #matchDataAuthority(Uri)} that allows wildcard matching of the provided
+ * authority.
+ *
+ * @param wildcardSupported if true, will allow parameters to use wildcards
+ * @hide
+ */
+ public final int matchDataAuthority(Uri data, boolean wildcardSupported) {
+ if (data == null || mDataAuthorities == null) {
return NO_MATCH_DATA;
}
final int numDataAuthorities = mDataAuthorities.size();
for (int i = 0; i < numDataAuthorities; i++) {
final AuthorityEntry ae = mDataAuthorities.get(i);
- int match = ae.match(data);
+ int match = ae.match(data, wildcardSupported);
if (match >= 0) {
return match;
}
@@ -1488,6 +1550,15 @@
* @see #match
*/
public final int matchData(String type, String scheme, Uri data) {
+ return matchData(type, scheme, data, false);
+ }
+
+ /**
+ * Variant of {@link #matchData(String, String, Uri)} that allows wildcard matching
+ * of the provided type, scheme, host and path parameters.
+ * @param wildcardSupported if true, will allow parameters to use wildcards
+ */
+ private int matchData(String type, String scheme, Uri data, boolean wildcardSupported) {
final ArrayList<String> types = mDataTypes;
final ArrayList<String> schemes = mDataSchemes;
@@ -1499,7 +1570,8 @@
}
if (schemes != null) {
- if (schemes.contains(scheme != null ? scheme : "")) {
+ if (schemes.contains(scheme != null ? scheme : "")
+ || wildcardSupported && WILDCARD.equals(scheme)) {
match = MATCH_CATEGORY_SCHEME;
} else {
return NO_MATCH_DATA;
@@ -1507,19 +1579,19 @@
final ArrayList<PatternMatcher> schemeSpecificParts = mDataSchemeSpecificParts;
if (schemeSpecificParts != null && data != null) {
- match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart())
+ match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart(), wildcardSupported)
? MATCH_CATEGORY_SCHEME_SPECIFIC_PART : NO_MATCH_DATA;
}
if (match != MATCH_CATEGORY_SCHEME_SPECIFIC_PART) {
// If there isn't any matching ssp, we need to match an authority.
final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
if (authorities != null) {
- int authMatch = matchDataAuthority(data);
+ int authMatch = matchDataAuthority(data, wildcardSupported);
if (authMatch >= 0) {
final ArrayList<PatternMatcher> paths = mDataPaths;
if (paths == null) {
match = authMatch;
- } else if (hasDataPath(data.getPath())) {
+ } else if (hasDataPath(data.getPath(), wildcardSupported)) {
match = MATCH_CATEGORY_PATH;
} else {
return NO_MATCH_DATA;
@@ -1541,7 +1613,8 @@
// to force everyone to say they handle content: or file: URIs.
if (scheme != null && !"".equals(scheme)
&& !"content".equals(scheme)
- && !"file".equals(scheme)) {
+ && !"file".equals(scheme)
+ && !(wildcardSupported && WILDCARD.equals(scheme))) {
return NO_MATCH_DATA;
}
}
@@ -1701,13 +1774,23 @@
*/
public final int match(String action, String type, String scheme,
Uri data, Set<String> categories, String logTag) {
- if (action != null && !matchAction(action)) {
+ return match(action, type, scheme, data, categories, logTag, false /*supportWildcards*/);
+ }
+
+ /**
+ * Variant of {@link #match(ContentResolver, Intent, boolean, String)} that supports wildcards
+ * in the action, type, scheme, host and path.
+ * @hide if true, will allow supported parameters to use wildcards to match this filter
+ */
+ public final int match(String action, String type, String scheme,
+ Uri data, Set<String> categories, String logTag, boolean supportWildcards) {
+ if (action != null && !matchAction(action, supportWildcards)) {
if (false) Log.v(
logTag, "No matching action " + action + " for " + this);
return NO_MATCH_ACTION;
}
- int dataMatch = matchData(type, scheme, data);
+ int dataMatch = matchData(type, scheme, data, supportWildcards);
if (dataMatch < 0) {
if (false) {
if (dataMatch == NO_MATCH_TYPE) {
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 3261cb1..5e7e0c8 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -27,6 +27,7 @@
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -128,6 +129,35 @@
@NonNull Intent intent,
@NonNull UserHandle targetUser,
@Nullable Activity callingActivity) {
+ startActivity(intent, targetUser, callingActivity, /* options= */ null);
+ }
+
+ /**
+ * Starts the specified activity of the caller package in the specified profile.
+ *
+ * <p>The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES},
+ * {@code android.Manifest.permission#INTERACT_ACROSS_USERS}, or {@code
+ * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission. Both the caller and
+ * target user profiles must be in the same profile group. The target user must be a valid user
+ * returned from {@link #getTargetUserProfiles()}.
+ *
+ * @param intent The intent to launch. A component in the caller package must be specified.
+ * @param targetUser The {@link UserHandle} of the profile; must be one of the users returned by
+ * {@link #getTargetUserProfiles()} if different to the calling user, otherwise a
+ * {@link SecurityException} will be thrown.
+ * @param callingActivity The activity to start the new activity from for the purposes of
+ * deciding which task the new activity should belong to. If {@code null}, the activity
+ * will always be started in a new task.
+ * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
+ public void startActivity(
+ @NonNull Intent intent,
+ @NonNull UserHandle targetUser,
+ @Nullable Activity callingActivity,
+ @Nullable Bundle options) {
try {
mService.startActivityAsUserByIntent(
mContext.getIApplicationThread(),
@@ -135,7 +165,8 @@
mContext.getFeatureId(),
intent,
targetUser.getIdentifier(),
- callingActivity != null ? callingActivity.getActivityToken() : null);
+ callingActivity != null ? callingActivity.getActivityToken() : null,
+ options);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index 5a6e008..4cecb30 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -31,7 +31,8 @@
in String callingFeatureId, in ComponentName component, int userId,
boolean launchMainActivity);
void startActivityAsUserByIntent(in IApplicationThread caller, in String callingPackage,
- in String callingFeatureId, in Intent intent, int userId, in IBinder callingActivity);
+ in String callingFeatureId, in Intent intent, int userId, in IBinder callingActivity,
+ in Bundle options);
List<UserHandle> getTargetUserProfiles(in String callingPackage);
boolean canInteractAcrossProfiles(in String callingPackage);
boolean canRequestInteractAcrossProfiles(in String callingPackage);
diff --git a/core/java/android/content/pm/InstallSourceInfo.java b/core/java/android/content/pm/InstallSourceInfo.java
index c0fdcc9..a45bf79 100644
--- a/core/java/android/content/pm/InstallSourceInfo.java
+++ b/core/java/android/content/pm/InstallSourceInfo.java
@@ -66,7 +66,18 @@
mInstallingPackageName = source.readString();
}
- /** The name of the package that requested the installation, or null if not available. */
+ /**
+ * The name of the package that requested the installation, or null if not available.
+ *
+ * This is normally the same as the installing package name. If the installing package name
+ * is changed, for example by calling
+ * {@link PackageManager#setInstallerPackageName(String, String)}, the initiating package name
+ * remains unchanged. It continues to identify the actual package that performed the install
+ * or update.
+ * <p>
+ * Null may be returned if the app was not installed by a package (e.g. a system app or an app
+ * installed via adb) or if the initiating package has itself been uninstalled.
+ */
@Nullable
public String getInitiatingPackageName() {
return mInitiatingPackageName;
@@ -100,9 +111,11 @@
/**
* The name of the package responsible for the installation (the installer of record), or null
* if not available.
- * Note that this may differ from the initiating package name and can be modified.
- *
- * @see PackageManager#setInstallerPackageName(String, String)
+ * Note that this may differ from the initiating package name and can be modified via
+ * {@link PackageManager#setInstallerPackageName(String, String)}.
+ * <p>
+ * Null may be returned if the app was not installed by a package (e.g. a system app or an app
+ * installed via adb) or if the installing package has itself been uninstalled.
*/
@Nullable
public String getInstallingPackageName() {
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 49e8c05..af87578 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1558,11 +1558,6 @@
* "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
* {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
*
- * <p>Because static shortcuts and dynamic shortcuts have overlapping ranks,
- * when a launcher app shows shortcuts for an activity, it should first show
- * the static shortcuts, followed by the dynamic shortcuts. Within each of those categories,
- * shortcuts should be sorted by rank in ascending order.
- *
* <p><em>Floating shortcuts</em>, or shortcuts that are neither static nor dynamic, will all
* have rank 0, because they aren't sorted.
*
diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java
index ede264d..578d53b 100644
--- a/core/java/android/database/ContentObserver.java
+++ b/core/java/android/database/ContentObserver.java
@@ -19,6 +19,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver.NotifyFlags;
import android.net.Uri;
@@ -26,12 +29,26 @@
import android.os.UserHandle;
import java.util.Arrays;
+import java.util.Collection;
/**
* Receives call backs for changes to content.
* Must be implemented by objects which are added to a {@link ContentObservable}.
*/
public abstract class ContentObserver {
+ /**
+ * Starting in {@link android.os.Build.VERSION_CODES#R}, there is a new
+ * public API overload {@link #onChange(boolean, Uri, int)} that delivers a
+ * {@code int flags} argument.
+ * <p>
+ * Some apps may be relying on a previous hidden API that delivered a
+ * {@code int userId} argument, and this change is used to control delivery
+ * of the new {@code int flags} argument in its place.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q)
+ private static final long ADD_CONTENT_OBSERVER_FLAGS = 150939131L;
+
private final Object mLock = new Object();
private Transport mTransport; // guarded by mLock
@@ -164,16 +181,26 @@
* @param uris The Uris of the changed content.
* @param flags Flags indicating details about this change.
*/
- public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags) {
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
+ @NotifyFlags int flags) {
for (Uri uri : uris) {
onChange(selfChange, uri, flags);
}
}
/** @hide */
- public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags,
- @UserIdInt int userId) {
- onChange(selfChange, uris, flags);
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
+ @NotifyFlags int flags, @UserIdInt int userId) {
+ // There are dozens of people relying on the hidden API inside the
+ // system UID, so hard-code the old behavior for all of them; for
+ // everyone else we gate based on a specific change
+ if (!CompatChanges.isChangeEnabled(ADD_CONTENT_OBSERVER_FLAGS)
+ || android.os.Process.myUid() == android.os.Process.SYSTEM_UID) {
+ // Deliver userId through argument to preserve hidden API behavior
+ onChange(selfChange, uris, userId);
+ } else {
+ onChange(selfChange, uris, flags);
+ }
}
/**
@@ -186,7 +213,7 @@
*
* @deprecated Callers should migrate towards using a richer overload that
* provides more details about the change, such as
- * {@link #dispatchChange(boolean, Iterable, int)}.
+ * {@link #dispatchChange(boolean, Collection, int)}.
*/
@Deprecated
public final void dispatchChange(boolean selfChange) {
@@ -206,7 +233,7 @@
* @param uri The Uri of the changed content.
*/
public final void dispatchChange(boolean selfChange, @Nullable Uri uri) {
- dispatchChange(selfChange, Arrays.asList(uri), 0, UserHandle.getCallingUserId());
+ dispatchChange(selfChange, uri, 0);
}
/**
@@ -224,7 +251,7 @@
*/
public final void dispatchChange(boolean selfChange, @Nullable Uri uri,
@NotifyFlags int flags) {
- dispatchChange(selfChange, Arrays.asList(uri), flags, UserHandle.getCallingUserId());
+ dispatchChange(selfChange, Arrays.asList(uri), flags);
}
/**
@@ -240,13 +267,13 @@
* @param uris The Uri of the changed content.
* @param flags Flags indicating details about this change.
*/
- public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+ public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
@NotifyFlags int flags) {
dispatchChange(selfChange, uris, flags, UserHandle.getCallingUserId());
}
/** @hide */
- public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+ public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
@NotifyFlags int flags, @UserIdInt int userId) {
if (mHandler == null) {
onChange(selfChange, uris, flags, userId);
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index 1855dd2..ce86807 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -20,10 +20,12 @@
import android.annotation.UserIdInt;
import android.content.ContentResolver.NotifyFlags;
import android.net.Uri;
-import android.os.*;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
import java.util.ArrayList;
-
+import java.util.Collection;
/**
* Wraps a BulkCursor around an existing Cursor making it remotable.
@@ -81,7 +83,7 @@
}
@Override
- public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
@NotifyFlags int flags, @UserIdInt int userId) {
// Since we deliver changes from the most-specific to least-specific
// overloads, we only need to redirect from the most-specific local
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 85ef4a3..a091f84 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -846,6 +846,33 @@
@NonNull String physicalCameraId) {
// default empty implementation
}
+
+ /**
+ * A camera device has been opened by an application.
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param cameraId The unique identifier of the new camera.
+ * @param packageId The package Id of the application opening the camera.
+ *
+ * @see #onCameraClosed
+ */
+ /** @hide */
+ public void onCameraOpened(@NonNull String cameraId, @NonNull String packageId) {
+ // default empty implementation
+ }
+
+ /**
+ * A previously-opened camera has been closed.
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param cameraId The unique identifier of the closed camera.
+ */
+ /** @hide */
+ public void onCameraClosed(@NonNull String cameraId) {
+ // default empty implementation
+ }
}
/**
@@ -1276,6 +1303,12 @@
}
@Override
public void onCameraAccessPrioritiesChanged() {
+ }
+ @Override
+ public void onCameraOpened(String id, String clientPackageId) {
+ }
+ @Override
+ public void onCameraClosed(String id) {
}};
String[] cameraIds = null;
@@ -1503,6 +1536,38 @@
}
}
+ private void postSingleCameraOpenedUpdate(final AvailabilityCallback callback,
+ final Executor executor, final String id, final String packageId) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(
+ new Runnable() {
+ @Override
+ public void run() {
+ callback.onCameraOpened(id, packageId);
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private void postSingleCameraClosedUpdate(final AvailabilityCallback callback,
+ final Executor executor, final String id) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(
+ new Runnable() {
+ @Override
+ public void run() {
+ callback.onCameraClosed(id);
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor,
final String id, final String physicalId, final int status) {
if (isAvailable(status)) {
@@ -1846,6 +1911,32 @@
}
}
+ @Override
+ public void onCameraOpened(String cameraId, String clientPackageId) {
+ synchronized (mLock) {
+ final int callbackCount = mCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ Executor executor = mCallbackMap.valueAt(i);
+ final AvailabilityCallback callback = mCallbackMap.keyAt(i);
+
+ postSingleCameraOpenedUpdate(callback, executor, cameraId, clientPackageId);
+ }
+ }
+ }
+
+ @Override
+ public void onCameraClosed(String cameraId) {
+ synchronized (mLock) {
+ final int callbackCount = mCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ Executor executor = mCallbackMap.valueAt(i);
+ final AvailabilityCallback callback = mCallbackMap.keyAt(i);
+
+ postSingleCameraClosedUpdate(callback, executor, cameraId);
+ }
+ }
+ }
+
/**
* Try to connect to camera service after some delay if any client registered camera
* availability callback or torch status callback.
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
index c5cb803..e90b57c 100644
--- a/core/java/android/hardware/lights/Light.java
+++ b/core/java/android/hardware/lights/Light.java
@@ -37,7 +37,8 @@
/**
* Creates a new light with the given data.
*
- * @hide */
+ * @hide
+ */
public Light(int id, int ordinal, int type) {
mId = id;
mOrdinal = ordinal;
@@ -76,8 +77,24 @@
}
};
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Light) {
+ Light light = (Light) obj;
+ return mId == light.mId && mOrdinal == light.mOrdinal && mType == light.mType;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mId;
+ }
+
/**
* Returns the id of the light.
+ *
+ * <p>This is an opaque value used as a unique identifier for the light.
*/
public int getId() {
return mId;
@@ -86,11 +103,9 @@
/**
* Returns the ordinal of the light.
*
- * <p>This represents the physical order of the lights on the device. The exact values are
- * device-dependent, but for example, if there are lights in a row, sorting the Light objects
- * by ordinal should match the order in which they appear on the device. If the device has
- * 4 lights, the ordinals could be [1, 2, 3, 4] or [0, 10, 20, 30] or any other values that
- * have the same sort order.
+ * <p>This is a sort key that represents the physical order of lights on the device with the
+ * same type. In the case of multiple lights arranged in a line, for example, the ordinals
+ * could be [1, 2, 3, 4], or [0, 10, 20, 30], or any other values that have the same sort order.
*/
public int getOrdinal() {
return mOrdinal;
diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java
index 1bc051b..8cd2312 100644
--- a/core/java/android/hardware/lights/LightsManager.java
+++ b/core/java/android/hardware/lights/LightsManager.java
@@ -161,7 +161,7 @@
* @param request the settings for lights that should change
*/
@RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
- public void setLights(@NonNull LightsRequest request) {
+ public void requestLights(@NonNull LightsRequest request) {
Preconditions.checkNotNull(request);
if (!mClosed) {
try {
diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java
index a36da4c..5c4fc67 100644
--- a/core/java/android/hardware/lights/LightsRequest.java
+++ b/core/java/android/hardware/lights/LightsRequest.java
@@ -86,7 +86,7 @@
* Create a LightsRequest object used to override lights on the device.
*
* <p>The generated {@link LightsRequest} should be used in
- * {@link LightsManager.Session#setLights(LightsLightsRequest).
+ * {@link LightsManager.Session#requestLights(LightsLightsRequest).
*/
public @NonNull LightsRequest build() {
return new LightsRequest(mChanges);
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index bf641d7..1aeb76a3 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -28,7 +28,6 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.Slog;
import android.util.Xml;
@@ -231,15 +230,7 @@
com.android.internal.R.styleable.VoiceEnrollmentApplication);
keyphraseMetadata = getKeyphraseFromTypedArray(array, packageName, parseErrors);
array.recycle();
- } catch (XmlPullParserException e) {
- String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
- parseErrors.add(error + ": " + e);
- Slog.w(TAG, error, e);
- } catch (IOException e) {
- String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
- parseErrors.add(error + ": " + e);
- Slog.w(TAG, error, e);
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (XmlPullParserException | PackageManager.NameNotFoundException | IOException e) {
String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
parseErrors.add(error + ": " + e);
Slog.w(TAG, error, e);
@@ -390,7 +381,6 @@
* False if not.
*/
public boolean isUidSupportedEnrollmentApplication(int uid) {
- Log.d(TAG, "isUidSupportedEnrollmentApplication: " + toString());
return mEnrollmentApplicationUids.contains(uid);
}
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index 0513fee..6efd03c 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -28,6 +28,7 @@
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.View;
import android.view.WindowManager;
import java.lang.annotation.Retention;
@@ -94,6 +95,13 @@
lp.token = token;
getWindow().setAttributes(lp);
updateWindowState(SoftInputWindowState.TOKEN_SET);
+
+ // As soon as we have a token, make sure the window is added (but not shown) by
+ // setting visibility to INVISIBLE and calling show() on Dialog. Note that
+ // WindowInsetsController.OnControllableInsetsChangedListener relies on the window
+ // being added to function.
+ getWindow().getDecorView().setVisibility(View.INVISIBLE);
+ show();
return;
case SoftInputWindowState.TOKEN_SET:
case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index dd3f9fd..20e5f24 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -526,7 +526,7 @@
final AppOpsManager.PausedNotedAppOpsCollection prevCollection =
AppOpsManager.pauseNotedAppOpsCollection();
- if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isCollectingNotedAppOps()) {
+ if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) {
flags |= FLAG_COLLECT_NOTED_APP_OPS;
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 21a1e0f..f2fb5b2 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -39,6 +39,7 @@
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
/**
* Provides access to environment variables.
@@ -1253,6 +1254,50 @@
uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
}
+ /**
+ * Returns whether the calling app has All Files Access on the primary shared/external storage
+ * media.
+ * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
+ * enough to gain the access.
+ * <p>To request access, use
+ * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
+ */
+ public static boolean isExternalStorageManager() {
+ final File externalDir = sCurrentUser.getExternalDirs()[0];
+ return isExternalStorageManager(externalDir);
+ }
+
+ /**
+ * Returns whether the calling app has All Files Access at the given {@code path}
+ * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
+ * enough to gain the access.
+ * <p>To request access, use
+ * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
+ */
+ public static boolean isExternalStorageManager(@NonNull File path) {
+ final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication());
+ String packageName = Objects.requireNonNull(context.getPackageName());
+ int uid = context.getApplicationInfo().uid;
+
+ final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
+ final int opMode =
+ appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName);
+
+ switch (opMode) {
+ case AppOpsManager.MODE_DEFAULT:
+ return PackageManager.PERMISSION_GRANTED
+ == context.checkPermission(
+ Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid);
+ case AppOpsManager.MODE_ALLOWED:
+ return true;
+ case AppOpsManager.MODE_ERRORED:
+ case AppOpsManager.MODE_IGNORED:
+ return false;
+ default:
+ throw new IllegalStateException("Unknown AppOpsManager mode " + opMode);
+ }
+ }
+
static File getDirectory(String variableName, String defaultPath) {
String path = System.getenv(variableName);
return path == null ? new File(defaultPath) : new File(path);
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index 1eb7664..dd2ea81 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -16,7 +16,6 @@
package android.provider;
import android.annotation.IntDef;
-import android.annotation.SystemApi;
import android.annotation.WorkerThread;
import android.content.Context;
import android.net.Uri;
@@ -240,7 +239,6 @@
* blocked.
* @hide
*/
- @SystemApi
public static final int STATUS_NOT_BLOCKED = 0;
/**
@@ -248,7 +246,6 @@
* because it is in the list of blocked numbers maintained by the provider.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_IN_LIST = 1;
/**
@@ -256,7 +253,6 @@
* because it is from a restricted number.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_RESTRICTED = 2;
/**
@@ -264,7 +260,6 @@
* because it is from an unknown number.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_UNKNOWN_NUMBER = 3;
/**
@@ -272,7 +267,6 @@
* because it is from a pay phone.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_PAYPHONE = 4;
/**
@@ -280,14 +274,12 @@
* because it is from a number not in the users contacts.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_NOT_IN_CONTACTS = 5;
/**
* Integer reason indicating whether a call was blocked, and if so why.
* @hide
*/
- @SystemApi
public static final String RES_BLOCK_STATUS = "block_status";
/** @hide */
@@ -298,31 +290,6 @@
"can_current_user_block_numbers";
/** @hide */
- @SystemApi
- public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
-
- /** @hide */
- public static final String METHOD_END_BLOCK_SUPPRESSION = "end_block_suppression";
-
- /** @hide */
- @SystemApi
- public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
-
- /** @hide */
- public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS =
- "get_block_suppression_status";
-
- /** @hide */
- public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION =
- "should_show_emergency_call_notification";
-
- /** @hide */
- public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting";
-
- /** @hide */
- public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting";
-
- /** @hide */
public static final String RES_CAN_BLOCK_NUMBERS = "can_block";
/** @hide */
@@ -439,11 +406,26 @@
public static final String ACTION_BLOCK_SUPPRESSION_STATE_CHANGED =
"android.provider.action.BLOCK_SUPPRESSION_STATE_CHANGED";
+ public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
+
+ public static final String METHOD_END_BLOCK_SUPPRESSION = "end_block_suppression";
+
+ public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
+
+ public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS =
+ "get_block_suppression_status";
+
+ public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION =
+ "should_show_emergency_call_notification";
+
public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed";
public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP =
"blocking_suppressed_until_timestamp";
+ public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting";
+ public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting";
+
/* Preference key of block numbers not in contacts setting. */
public static final String ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED =
"block_numbers_not_in_contacts_setting";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 641de4a..23c074c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -98,7 +98,8 @@
* The Settings provider contains global system-level device preferences.
*/
public final class Settings {
- private static final boolean DEFAULT_OVERRIDEABLE_BY_RESTORE = false;
+ /** @hide */
+ public static final boolean DEFAULT_OVERRIDEABLE_BY_RESTORE = false;
// Intent actions for Settings
@@ -709,10 +710,7 @@
* If not specified, the default behavior is
* {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_WEAK}.
* <p>
- * Output: Returns {@link android.app.Activity#RESULT_CANCELED} if the user already has an
- * authenticator that meets the requirements, or if the device cannot fulfill the request
- * (e.g. does not have biometric hardware). Returns {@link android.app.Activity#RESULT_OK}
- * otherwise. Note that callers should still check
+ * Output: Nothing. Note that callers should still check
* {@link android.hardware.biometrics.BiometricManager#canAuthenticate(int)}
* afterwards to ensure that the user actually completed enrollment.
*/
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 629dc8b..03b38ab 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3735,7 +3735,6 @@
* @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
*/
@Deprecated
- @SystemApi
public static final String BEARER_BITMASK = "bearer_bitmask";
/**
@@ -3785,7 +3784,6 @@
* <p>Type: INTEGER</p>
*@hide
*/
- @SystemApi
public static final String PROFILE_ID = "profile_id";
/**
@@ -3986,7 +3984,6 @@
*
* @hide
*/
- @SystemApi
public static final String SKIP_464XLAT = "skip_464xlat";
/**
@@ -3995,7 +3992,6 @@
*
* @hide
*/
- @SystemApi
public static final int SKIP_464XLAT_DEFAULT = -1;
/**
@@ -4004,7 +4000,6 @@
*
* @hide
*/
- @SystemApi
public static final int SKIP_464XLAT_DISABLE = 0;
/**
@@ -4013,7 +4008,6 @@
*
* @hide
*/
- @SystemApi
public static final int SKIP_464XLAT_ENABLE = 1;
@@ -4392,6 +4386,7 @@
* Indicates that whether the message has been broadcasted to the application.
* <P>Type: BOOLEAN</P>
*/
+ // TODO: deprecate this in S.
public static final String MESSAGE_BROADCASTED = "message_broadcasted";
/**
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 72e9ad0..8f858d5 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -77,6 +77,15 @@
*/
public static final @RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST = 0x2;
+ /**
+ * Indicates the request came from a password field.
+ *
+ * (TODO: b/141703197) Temporary fix for augmented autofill showing passwords.
+ *
+ * @hide
+ */
+ public static final @RequestFlags int FLAG_PASSWORD_INPUT_TYPE = 0x4;
+
/** @hide */
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -149,7 +158,8 @@
/** @hide */
@IntDef(flag = true, prefix = "FLAG_", value = {
FLAG_MANUAL_REQUEST,
- FLAG_COMPATIBILITY_MODE_REQUEST
+ FLAG_COMPATIBILITY_MODE_REQUEST,
+ FLAG_PASSWORD_INPUT_TYPE
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -169,6 +179,8 @@
return "FLAG_MANUAL_REQUEST";
case FLAG_COMPATIBILITY_MODE_REQUEST:
return "FLAG_COMPATIBILITY_MODE_REQUEST";
+ case FLAG_PASSWORD_INPUT_TYPE:
+ return "FLAG_PASSWORD_INPUT_TYPE";
default: return Integer.toHexString(value);
}
}
@@ -223,7 +235,8 @@
Preconditions.checkFlagsArgument(
mFlags,
FLAG_MANUAL_REQUEST
- | FLAG_COMPATIBILITY_MODE_REQUEST);
+ | FLAG_COMPATIBILITY_MODE_REQUEST
+ | FLAG_PASSWORD_INPUT_TYPE);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
onConstructed();
@@ -352,7 +365,8 @@
Preconditions.checkFlagsArgument(
mFlags,
FLAG_MANUAL_REQUEST
- | FLAG_COMPATIBILITY_MODE_REQUEST);
+ | FLAG_COMPATIBILITY_MODE_REQUEST
+ | FLAG_PASSWORD_INPUT_TYPE);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
onConstructed();
@@ -373,10 +387,10 @@
};
@DataClass.Generated(
- time = 1575928271155L,
+ time = 1583196707026L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index 0b9a8af..d4db79e 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
@@ -206,6 +207,7 @@
* @throws IOException if trouble opening the file for writing, such as lack of disk space
* or unavailable media.
*/
+ @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
public void writeData(@NonNull String name, long offsetBytes, long lengthBytes,
@NonNull ParcelFileDescriptor incomingFd) throws IOException {
try {
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 002d4b8..e70311f 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -609,9 +609,7 @@
*
* @hide
*
- * TODO: Remove @UnsupportedAppUsage.
*/
- @UnsupportedAppUsage
public void setWindowless(boolean windowless) {
mWindowless = windowless;
}
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 74b9136..1beeb65 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -237,16 +237,24 @@
public StatusBarNotification cloneLight() {
final Notification no = new Notification();
this.notification.cloneInto(no, false); // light copy
- return new StatusBarNotification(this.pkg, this.opPkg,
- this.id, this.tag, this.uid, this.initialPid,
- no, this.user, this.overrideGroupKey, this.postTime);
+ return cloneShallow(no);
}
@Override
public StatusBarNotification clone() {
- return new StatusBarNotification(this.pkg, this.opPkg,
+ return cloneShallow(this.notification.clone());
+ }
+
+ /**
+ * @param notification Some kind of clone of this.notification.
+ * @return A shallow copy of self, with notification in place of this.notification.
+ */
+ StatusBarNotification cloneShallow(Notification notification) {
+ StatusBarNotification result = new StatusBarNotification(this.pkg, this.opPkg,
this.id, this.tag, this.uid, this.initialPid,
- this.notification.clone(), this.user, this.overrideGroupKey, this.postTime);
+ notification, this.user, this.overrideGroupKey, this.postTime);
+ result.setInstanceId(this.mInstanceId);
+ return result;
}
@Override
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index bf3c088..f531e12 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -124,8 +124,6 @@
private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050;
private static final int MSG_SCALE = 10100;
- private static final float MAX_SCALE = 1.15f;
-
private static final int NOTIFY_COLORS_RATE_LIMIT_MS = 1000;
private final ArrayList<Engine> mActiveEngines
@@ -351,7 +349,7 @@
@Override
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync) {
+ float zoom, boolean sync) {
synchronized (mLock) {
if (DEBUG) Log.v(TAG, "Dispatch wallpaper offsets: " + x + ", " + y);
mPendingXOffset = x;
@@ -366,6 +364,8 @@
Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
mCaller.sendMessage(msg);
}
+ Message msg = mCaller.obtainMessageI(MSG_SCALE, Float.floatToIntBits(zoom));
+ mCaller.sendMessage(msg);
}
}
@@ -462,6 +462,18 @@
}
/**
+ * This will be called when the wallpaper is first started. If true is returned, the system
+ * will zoom in the wallpaper by default and zoom it out as the user interacts,
+ * to create depth. Otherwise, zoom will have to be handled manually
+ * in {@link #onZoomChanged(float)}.
+ *
+ * @hide
+ */
+ public boolean shouldZoomOutWallpaper() {
+ return false;
+ }
+
+ /**
* Control whether this wallpaper will receive raw touch events
* from the window manager as the user interacts with the window
* that is currently displaying the wallpaper. By default they
@@ -870,6 +882,7 @@
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
+ mSession.setShouldZoomOutWallpaper(mWindow, shouldZoomOutWallpaper());
mCreated = true;
mInputEventReceiver = new WallpaperInputEventReceiver(
@@ -964,7 +977,6 @@
c.surfaceCreated(mSurfaceHolder);
}
}
- onZoomChanged(0f);
}
redrawNeeded |= creating || (relayoutResult
@@ -1125,7 +1137,6 @@
mIsInAmbientMode = inAmbientMode;
if (mCreated) {
onAmbientModeChanged(inAmbientMode, animationDuration);
- setZoom(0);
}
}
}
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index 2aca36a..82c7ea7 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.telephony.PhoneNumberUtils;
@@ -663,9 +664,11 @@
private static void gatherTelLinks(ArrayList<LinkSpec> links, Spannable s,
@Nullable Context context) {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
+ final Context ctx = (context != null) ? context : ActivityThread.currentApplication();
+ final String regionCode = (ctx != null) ? ctx.getSystemService(TelephonyManager.class).
+ getSimCountryIso().toUpperCase(Locale.US) : Locale.getDefault().getCountry();
Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
- TelephonyManager.getDefaultSimCountryIso().toUpperCase(Locale.US),
- Leniency.POSSIBLE, Long.MAX_VALUE);
+ regionCode, Leniency.POSSIBLE, Long.MAX_VALUE);
for (PhoneNumberMatch match : matches) {
LinkSpec spec = new LinkSpec();
spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
diff --git a/core/java/android/view/ITaskOrganizer.aidl b/core/java/android/view/ITaskOrganizer.aidl
index 5ccdd30..565f694 100644
--- a/core/java/android/view/ITaskOrganizer.aidl
+++ b/core/java/android/view/ITaskOrganizer.aidl
@@ -27,7 +27,7 @@
*/
oneway interface ITaskOrganizer {
void taskAppeared(in ActivityManager.RunningTaskInfo taskInfo);
- void taskVanished(in IWindowContainer container);
+ void taskVanished(in ActivityManager.RunningTaskInfo taskInfo);
/**
* Called upon completion of
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3927ebf..9f2d36d 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -102,9 +102,9 @@
void closeSystemDialogs(String reason);
/**
- * Called for wallpaper windows when their offsets change.
+ * Called for wallpaper windows when their offsets or zoom level change.
*/
- void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync);
+ void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync);
void dispatchWallpaperCommand(String action, int x, int y,
int z, in Bundle extras, boolean sync);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 91000a9..dfe89a3 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -221,6 +221,19 @@
*/
void setWallpaperPosition(IBinder windowToken, float x, float y, float xstep, float ystep);
+ /**
+ * For wallpaper windows, sets the scale of the wallpaper based on
+ * SystemUI behavior.
+ */
+ void setWallpaperZoomOut(IBinder windowToken, float scale);
+
+ /**
+ * For wallpaper windows, sets whether the wallpaper should actually be
+ * scaled when setWallpaperZoomOut is called. If set to false, the WallpaperService will
+ * receive the zoom out value but the surface won't be scaled.
+ */
+ void setShouldZoomOutWallpaper(IBinder windowToken, boolean shouldZoom);
+
@UnsupportedAppUsage
void wallpaperOffsetsComplete(IBinder window);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 302d4f3..607886f 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -52,6 +52,7 @@
import android.view.animation.PathInterpolator;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -59,6 +60,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.function.BiFunction;
/**
@@ -306,6 +308,11 @@
private SyncRtSurfaceTransactionApplier mApplier;
private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
+ private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
+ = new ArrayList<>();
+
+ /** Set of inset types for which an animation was started since last resetting this field */
+ private @InsetsType int mLastStartedAnimTypes;
public InsetsController(ViewRootImpl viewRoot) {
this(viewRoot, (controller, type) -> {
@@ -459,6 +466,13 @@
}
mTmpControlArray.clear();
+
+ // Do not override any animations that the app started in the OnControllableInsetsChanged
+ // listeners.
+ int animatingTypes = invokeControllableInsetsChangedListeners();
+ showTypes[0] &= ~animatingTypes;
+ hideTypes[0] &= ~animatingTypes;
+
if (showTypes[0] != 0) {
applyAnimation(showTypes[0], true /* show */, false /* fromIme */);
}
@@ -542,9 +556,7 @@
private CancellationSignal controlWindowInsetsAnimation(@InsetsType int types,
WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs,
@Nullable Interpolator interpolator, @AnimationType int animationType) {
- // If the frame of our window doesn't span the entire display, the control API makes very
- // little sense, as we don't deal with negative insets. So just cancel immediately.
- if (!mState.getDisplayFrame().equals(mFrame)) {
+ if (!checkDisplayFramesForControlling()) {
listener.onCancelled();
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.cancel();
@@ -554,6 +566,13 @@
false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types));
}
+ private boolean checkDisplayFramesForControlling() {
+
+ // If the frame of our window doesn't span the entire display, the control API makes very
+ // little sense, as we don't deal with negative insets. So just cancel immediately.
+ return mState.getDisplayFrame().equals(mFrame);
+ }
+
private CancellationSignal controlAnimationUnchecked(@InsetsType int types,
WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
long durationMs, Interpolator interpolator, boolean fade,
@@ -567,6 +586,7 @@
return cancellationSignal;
}
cancelExistingControllers(types);
+ mLastStartedAnimTypes |= types;
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
@@ -994,6 +1014,48 @@
return mViewRoot.mWindowAttributes.insetsFlags.behavior;
}
+ private @InsetsType int calculateControllableTypes() {
+ if (!checkDisplayFramesForControlling()) {
+ return 0;
+ }
+ @InsetsType int result = 0;
+ for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
+ InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
+ if (consumer.getControl() != null) {
+ result |= toPublicType(consumer.mType);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @return The types that are now animating due to a listener invoking control/show/hide
+ */
+ private @InsetsType int invokeControllableInsetsChangedListeners() {
+ mLastStartedAnimTypes = 0;
+ @InsetsType int types = calculateControllableTypes();
+ int size = mControllableInsetsChangedListeners.size();
+ for (int i = 0; i < size; i++) {
+ mControllableInsetsChangedListeners.get(i).onControllableInsetsChanged(this, types);
+ }
+ return mLastStartedAnimTypes;
+ }
+
+ @Override
+ public void addOnControllableInsetsChangedListener(
+ OnControllableInsetsChangedListener listener) {
+ Objects.requireNonNull(listener);
+ mControllableInsetsChangedListeners.add(listener);
+ listener.onControllableInsetsChanged(this, calculateControllableTypes());
+ }
+
+ @Override
+ public void removeOnControllableInsetsChangedListener(
+ OnControllableInsetsChangedListener listener) {
+ Objects.requireNonNull(listener);
+ mControllableInsetsChangedListeners.remove(listener);
+ }
+
/**
* At the time we receive new leashes (e.g. InsetsSourceConsumer is processing
* setControl) we need to release the old leash. But we may have already scheduled
diff --git a/core/java/android/view/PendingInsetsController.java b/core/java/android/view/PendingInsetsController.java
index c0ed935..7f36418 100644
--- a/core/java/android/view/PendingInsetsController.java
+++ b/core/java/android/view/PendingInsetsController.java
@@ -38,6 +38,8 @@
private @Behavior int mBehavior = KEEP_BEHAVIOR;
private final InsetsState mDummyState = new InsetsState();
private InsetsController mReplayedInsetsController;
+ private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
+ = new ArrayList<>();
@Override
public void show(int types) {
@@ -112,6 +114,27 @@
return mDummyState;
}
+ @Override
+ public void addOnControllableInsetsChangedListener(
+ OnControllableInsetsChangedListener listener) {
+ if (mReplayedInsetsController != null) {
+ mReplayedInsetsController.addOnControllableInsetsChangedListener(listener);
+ } else {
+ mControllableInsetsChangedListeners.add(listener);
+ listener.onControllableInsetsChanged(this, 0);
+ }
+ }
+
+ @Override
+ public void removeOnControllableInsetsChangedListener(
+ OnControllableInsetsChangedListener listener) {
+ if (mReplayedInsetsController != null) {
+ mReplayedInsetsController.removeOnControllableInsetsChangedListener(listener);
+ } else {
+ mControllableInsetsChangedListeners.remove(listener);
+ }
+ }
+
/**
* Replays the commands on {@code controller} and attaches it to this instance such that any
* calls will be forwarded to the real instance in the future.
@@ -128,9 +151,15 @@
for (int i = 0; i < size; i++) {
mRequests.get(i).replay(controller);
}
+ size = mControllableInsetsChangedListeners.size();
+ for (int i = 0; i < size; i++) {
+ controller.addOnControllableInsetsChangedListener(
+ mControllableInsetsChangedListeners.get(i));
+ }
// Reset all state so it doesn't get applied twice just in case
mRequests.clear();
+ mControllableInsetsChangedListeners.clear();
mBehavior = KEEP_BEHAVIOR;
mAppearance = 0;
mAppearanceMask = 0;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9228fbd..26ac4fc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5699,9 +5699,9 @@
mTranslator.translateEventInScreenToAppWindow(event);
}
- // Enter touch mode if event is coming from a touch screen device.
+ // Enter touch mode on down or scroll from any type of a device.
final int action = event.getAction();
- if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
+ if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
ensureTouchMode(true);
}
@@ -9054,7 +9054,7 @@
@Override
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync) {
+ float zoom, boolean sync) {
if (sync) {
try {
mWindowSession.wallpaperOffsetsComplete(asBinder());
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index b7ca037..2ad557e 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -20,7 +20,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Insets;
+import android.inputmethodservice.InputMethodService;
import android.os.CancellationSignal;
+import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.animation.Interpolator;
@@ -212,4 +214,55 @@
* @hide
*/
InsetsState getState();
+
+ /**
+ * Adds a {@link OnControllableInsetsChangedListener} to the window insets controller.
+ *
+ * @param listener The listener to add.
+ *
+ * @see OnControllableInsetsChangedListener
+ * @see #removeOnControllableInsetsChangedListener(OnControllableInsetsChangedListener)
+ */
+ void addOnControllableInsetsChangedListener(
+ @NonNull OnControllableInsetsChangedListener listener);
+
+ /**
+ * Removes a {@link OnControllableInsetsChangedListener} from the window insets controller.
+ *
+ * @param listener The listener to remove.
+ *
+ * @see OnControllableInsetsChangedListener
+ * @see #addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener)
+ */
+ void removeOnControllableInsetsChangedListener(
+ @NonNull OnControllableInsetsChangedListener listener);
+
+ /**
+ * Listener to be notified when the set of controllable {@link InsetsType} controlled by a
+ * {@link WindowInsetsController} changes.
+ * <p>
+ * Once a {@link InsetsType} becomes controllable, the app will be able to control the window
+ * that is causing this type of insets by calling {@link #controlWindowInsetsAnimation}.
+ * <p>
+ * Note: When listening to controllability of the {@link Type#ime},
+ * {@link #controlWindowInsetsAnimation} may still fail in case the {@link InputMethodService}
+ * decides to cancel the show request. This could happen when there is a hardware keyboard
+ * attached.
+ *
+ * @see #addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener)
+ * @see #removeOnControllableInsetsChangedListener(OnControllableInsetsChangedListener)
+ */
+ interface OnControllableInsetsChangedListener {
+
+ /**
+ * Called when the set of controllable {@link InsetsType} changes.
+ *
+ * @param controller The controller for which the set of controllable {@link InsetsType}s
+ * are changing.
+ * @param typeMask Bitwise type-mask of the {@link InsetsType}s the controller is currently
+ * able to control.
+ */
+ void onControllableInsetsChanged(@NonNull WindowInsetsController controller,
+ @InsetsType int typeMask);
+ }
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 867b648..c5fa3c8 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -805,6 +805,7 @@
@ViewDebug.IntToString(from = TYPE_APPLICATION_OVERLAY,
to = "APPLICATION_OVERLAY")
})
+ @WindowType
public int type;
/**
@@ -1244,13 +1245,47 @@
public static final int INVALID_WINDOW_TYPE = -1;
/**
+ * @hide
+ */
+ @IntDef(prefix = "TYPE_", value = {
+ TYPE_ACCESSIBILITY_OVERLAY,
+ TYPE_APPLICATION,
+ TYPE_APPLICATION_ATTACHED_DIALOG,
+ TYPE_APPLICATION_MEDIA,
+ TYPE_APPLICATION_OVERLAY,
+ TYPE_APPLICATION_PANEL,
+ TYPE_APPLICATION_STARTING,
+ TYPE_APPLICATION_SUB_PANEL,
+ TYPE_BASE_APPLICATION,
+ TYPE_DRAWN_APPLICATION,
+ TYPE_INPUT_METHOD,
+ TYPE_INPUT_METHOD_DIALOG,
+ TYPE_KEYGUARD,
+ TYPE_KEYGUARD_DIALOG,
+ TYPE_PHONE,
+ TYPE_PRIORITY_PHONE,
+ TYPE_PRIVATE_PRESENTATION,
+ TYPE_SEARCH_BAR,
+ TYPE_STATUS_BAR,
+ TYPE_STATUS_BAR_PANEL,
+ TYPE_SYSTEM_ALERT,
+ TYPE_SYSTEM_DIALOG,
+ TYPE_SYSTEM_ERROR,
+ TYPE_SYSTEM_OVERLAY,
+ TYPE_TOAST,
+ TYPE_WALLPAPER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WindowType {}
+
+ /**
* Return true if the window type is an alert window.
*
* @param type The window type.
* @return If the window type is an alert window.
* @hide
*/
- public static boolean isSystemAlertWindowType(int type) {
+ public static boolean isSystemAlertWindowType(@WindowType int type) {
switch (type) {
case TYPE_PHONE:
case TYPE_PRIORITY_PHONE:
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 87dcba0..144f8e3 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -312,6 +312,14 @@
}
@Override
+ public void setWallpaperZoomOut(android.os.IBinder windowToken, float zoom) {
+ }
+
+ @Override
+ public void setShouldZoomOutWallpaper(android.os.IBinder windowToken, boolean shouldZoom) {
+ }
+
+ @Override
public void wallpaperOffsetsComplete(android.os.IBinder window) {
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index ce7cfa7..dda4e8b 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -17,6 +17,7 @@
package android.view.autofill;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
import static android.view.autofill.Helper.toList;
@@ -63,6 +64,7 @@
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityWindowInfo;
import android.widget.EditText;
+import android.widget.TextView;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
@@ -983,6 +985,10 @@
if (!isClientDisablingEnterExitEvent()) {
final AutofillValue value = view.getAutofillValue();
+ if (view instanceof TextView && ((TextView) view).isAnyPasswordInputType()) {
+ flags |= FLAG_PASSWORD_INPUT_TYPE;
+ }
+
if (!isActiveLocked()) {
// Starts new session.
startSessionLocked(id, null, value, flags);
@@ -1149,6 +1155,10 @@
} else {
// don't notify entered when Activity is already in background
if (!isClientDisablingEnterExitEvent()) {
+ if (view instanceof TextView && ((TextView) view).isAnyPasswordInputType()) {
+ flags |= FLAG_PASSWORD_INPUT_TYPE;
+ }
+
if (!isActiveLocked()) {
// Starts new session.
startSessionLocked(id, bounds, null, flags);
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index e50da40..8e8c7df 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -44,15 +44,15 @@
public static final int SUGGESTION_COUNT_UNLIMITED = Integer.MAX_VALUE;
/**
- * Max number of suggestions expected from the response. Defaults to {@code
- * SUGGESTION_COUNT_UNLIMITED} if not set.
+ * Max number of suggestions expected from the response. It must be a positive value.
+ * Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
*/
private final int mMaxSuggestionCount;
/**
* The {@link InlinePresentationSpec} for each suggestion in the response. If the max suggestion
* count is larger than the number of specs in the list, then the last spec is used for the
- * remainder of the suggestions.
+ * remainder of the suggestions. The list should not be empty.
*/
private final @NonNull List<InlinePresentationSpec> mPresentationSpecs;
@@ -72,6 +72,7 @@
/**
* The extras state propagated from the IME to pass extra data.
*/
+ @DataClass.MaySetToNull
private @Nullable Bundle mExtras;
/**
@@ -80,6 +81,7 @@
*
* @hide
*/
+ @DataClass.MaySetToNull
private @Nullable IBinder mHostInputToken;
/**
@@ -117,6 +119,7 @@
}
private void onConstructed() {
+ Preconditions.checkState(!mPresentationSpecs.isEmpty());
Preconditions.checkState(mMaxSuggestionCount >= mPresentationSpecs.size());
}
@@ -162,7 +165,7 @@
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -202,8 +205,8 @@
}
/**
- * Max number of suggestions expected from the response. Defaults to {@code
- * SUGGESTION_COUNT_UNLIMITED} if not set.
+ * Max number of suggestions expected from the response. It must be a positive value.
+ * Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
*/
@DataClass.Generated.Member
public int getMaxSuggestionCount() {
@@ -213,7 +216,7 @@
/**
* The {@link InlinePresentationSpec} for each suggestion in the response. If the max suggestion
* count is larger than the number of specs in the list, then the last spec is used for the
- * remainder of the suggestions.
+ * remainder of the suggestions. The list should not be empty.
*/
@DataClass.Generated.Member
public @NonNull List<InlinePresentationSpec> getPresentationSpecs() {
@@ -419,7 +422,7 @@
* @param presentationSpecs
* The {@link InlinePresentationSpec} for each suggestion in the response. If the max suggestion
* count is larger than the number of specs in the list, then the last spec is used for the
- * remainder of the suggestions.
+ * remainder of the suggestions. The list should not be empty.
*/
public Builder(
@NonNull List<InlinePresentationSpec> presentationSpecs) {
@@ -429,8 +432,8 @@
}
/**
- * Max number of suggestions expected from the response. Defaults to {@code
- * SUGGESTION_COUNT_UNLIMITED} if not set.
+ * Max number of suggestions expected from the response. It must be a positive value.
+ * Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
*/
@DataClass.Generated.Member
public @NonNull Builder setMaxSuggestionCount(int value) {
@@ -443,7 +446,7 @@
/**
* The {@link InlinePresentationSpec} for each suggestion in the response. If the max suggestion
* count is larger than the number of specs in the list, then the last spec is used for the
- * remainder of the suggestions.
+ * remainder of the suggestions. The list should not be empty.
*/
@DataClass.Generated.Member
@Override
@@ -575,10 +578,10 @@
}
@DataClass.Generated(
- time = 1582339908980L,
- codegenVersion = "1.0.14",
+ time = 1583975428858L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
- inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> mPresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.Nullable android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic void setHostInputToken(android.os.IBinder)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.Nullable android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setPresentationSpecs(java.util.List<android.view.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> mPresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @com.android.internal.util.DataClass.MaySetToNull @android.annotation.Nullable android.os.Bundle mExtras\nprivate @com.android.internal.util.DataClass.MaySetToNull @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic void setHostInputToken(android.os.IBinder)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.Nullable android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setPresentationSpecs(java.util.List<android.view.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index ff80ef7..f62a28e 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -268,17 +268,28 @@
protected abstract boolean allowFileSchemeCookiesImpl();
/**
- * Sets whether the application's {@link WebView} instances should send and
- * accept cookies for file scheme URLs.
- * Use of cookies with file scheme URLs is potentially insecure and turned
- * off by default.
- * Do not use this feature unless you can be sure that no unintentional
- * sharing of cookie data can take place.
+ * Sets whether the application's {@link WebView} instances should send and accept cookies for
+ * file scheme URLs.
* <p>
- * Note that calls to this method will have no effect if made after a
- * {@link WebView} or CookieManager instance has been created.
+ * Use of cookies with file scheme URLs is potentially insecure and turned off by default. All
+ * {@code file://} URLs share all their cookies, which may lead to leaking private app cookies
+ * (ex. any malicious file can access cookies previously set by other (trusted) files).
+ * <p class="note">
+ * Loading content via {@code file://} URLs is generally discouraged. See the note in
+ * {@link WebSettings#setAllowFileAccess}.
+ * Using <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+ * androidx.webkit.WebViewAssetLoader</a> to load files over {@code http(s)://} URLs allows
+ * the standard web security model to be used for setting and sharing cookies for local files.
+ * <p>
+ * Note that calls to this method will have no effect if made after calling other
+ * {@link CookieManager} APIs.
+ *
+ * @deprecated This setting is not secure, please use
+ * <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+ * androidx.webkit.WebViewAssetLoader</a> instead.
*/
// Static for backward compatibility.
+ @Deprecated
public static void setAcceptFileSchemeCookies(boolean accept) {
getInstance().setAcceptFileSchemeCookiesImpl(accept);
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 53541f7..35dd576 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -983,48 +983,63 @@
public abstract void setJavaScriptEnabled(boolean flag);
/**
- * Sets whether JavaScript running in the context of a file scheme URL
- * should be allowed to access content from any origin. This includes
- * access to content from other file scheme URLs. See
- * {@link #setAllowFileAccessFromFileURLs}. To enable the most restrictive,
- * and therefore secure policy, this setting should be disabled.
- * Note that this setting affects only JavaScript access to file scheme
- * resources. Other access to such resources, for example, from image HTML
- * elements, is unaffected. To prevent possible violation of same domain policy
- * when targeting {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier,
- * you should explicitly set this value to {@code false}.
+ * Sets whether cross-origin requests in the context of a file scheme URL should be allowed to
+ * access content from <i>any</i> origin. This includes access to content from other file
+ * scheme URLs or web contexts. Note that some access such as image HTML elements doesn't
+ * follow same-origin rules and isn't affected by this setting.
+ * <p>
+ * <b>Don't</b> enable this setting if you open files that may be created or altered by
+ * external sources. Enabling this setting allows malicious scripts loaded in a {@code file://}
+ * context to launch cross-site scripting attacks, either accessing arbitrary local files
+ * including WebView cookies, app private data or even credentials used on arbitrary web sites.
+ * <p class="note">
+ * Loading content via {@code file://} URLs is generally discouraged. See the note in
+ * {@link #setAllowFileAccess}.
* <p>
* The default value is {@code true} for apps targeting
- * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
- * and {@code false} when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
- * and above.
+ * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below, and {@code false}
+ * when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN} and above. To prevent
+ * possible violation of same domain policy when targeting
+ * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier, you should
+ * explicitly set this value to {@code false}.
*
- * @param flag whether JavaScript running in the context of a file scheme
- * URL should be allowed to access content from any origin
+ * @param flag whether JavaScript running in the context of a file scheme URL should be allowed
+ * to access content from any origin
+ * @deprecated This setting is not secure, please use
+ * <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+ * androidx.webkit.WebViewAssetLoader</a> to load file content securely.
*/
+ @Deprecated
public abstract void setAllowUniversalAccessFromFileURLs(boolean flag);
/**
- * Sets whether JavaScript running in the context of a file scheme URL
- * should be allowed to access content from other file scheme URLs. To
- * enable the most restrictive, and therefore secure, policy this setting
- * should be disabled. Note that the value of this setting is ignored if
- * the value of {@link #getAllowUniversalAccessFromFileURLs} is {@code true}.
- * Note too, that this setting affects only JavaScript access to file scheme
- * resources. Other access to such resources, for example, from image HTML
- * elements, is unaffected. To prevent possible violation of same domain policy
- * when targeting {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier,
- * you should explicitly set this value to {@code false}.
+ * Sets whether cross-origin requests in the context of a file scheme URL should be allowed to
+ * access content from other file scheme URLs. Note that some accesses such as image HTML
+ * elements don't follow same-origin rules and aren't affected by this setting.
* <p>
- * The default value is {@code true} for apps targeting
- * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
- * and {@code false} when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
- * and above.
+ * <b>Don't</b> enable this setting if you open files that may be created or altered by
+ * external sources. Enabling this setting allows malicious scripts loaded in a {@code file://}
+ * context to access arbitrary local files including WebView cookies and app private data.
+ * <p class="note">
+ * Loading content via {@code file://} URLs is generally discouraged. See the note in
+ * {@link #setAllowFileAccess}.
+ * <p>
+ * Note that the value of this setting is ignored if the value of
+ * {@link #getAllowUniversalAccessFromFileURLs} is {@code true}. The default value is
+ * {@code true} for apps targeting {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1}
+ * and below, and {@code false} when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
+ * and above. To prevent possible violation of same domain policy when targeting
+ * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier, you should
+ * explicitly set this value to {@code false}.
*
* @param flag whether JavaScript running in the context of a file scheme
* URL should be allowed to access content from other file
* scheme URLs
+ * @deprecated This setting is not secure, please use
+ * <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+ * androidx.webkit.WebViewAssetLoader</a> to load file content securely.
*/
+ @Deprecated
public abstract void setAllowFileAccessFromFileURLs(boolean flag);
/**
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index d165bd0..ffdb89d 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -261,7 +261,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
- String tz = intent.getStringExtra("time-zone");
+ String tz = intent.getStringExtra(Intent.EXTRA_TIMEZONE);
mClock = Clock.system(ZoneId.of(tz));
}
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 8565493..6432438 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -173,7 +173,7 @@
return; // Test disabled the clock ticks
}
if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
- final String timeZone = intent.getStringExtra("time-zone");
+ final String timeZone = intent.getStringExtra(Intent.EXTRA_TIMEZONE);
createTime(timeZone);
} else if (!mShouldRunTicker && (Intent.ACTION_TIME_TICK.equals(intent.getAction())
|| Intent.ACTION_TIME_CHANGED.equals(intent.getAction()))) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0d82065..2168018 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6607,6 +6607,16 @@
return mTransformation instanceof PasswordTransformationMethod;
}
+ /**
+ * Returns true if the current inputType is any type of password.
+ *
+ * @hide
+ */
+ public boolean isAnyPasswordInputType() {
+ final int inputType = getInputType();
+ return isPasswordInputType(inputType) || isVisiblePasswordInputType(inputType);
+ }
+
static boolean isPasswordInputType(int inputType) {
final int variation =
inputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION);
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 5cdcab0..54ea57a 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -56,6 +56,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -133,7 +134,7 @@
// Keep track of state of shortcut settings
final ContentObserver co = new ContentObserver(handler) {
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
if (userId == mUserId) {
onSettingsChanged();
}
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index d50826f..fa567f2 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -452,7 +452,7 @@
mEmptyStateView = rootView.findViewById(R.id.resolver_empty_state);
}
- private ViewGroup getEmptyStateView() {
+ protected ViewGroup getEmptyStateView() {
return mEmptyStateView;
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index c487e96..5620bff 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2398,17 +2398,22 @@
}
final int availableWidth = right - left - v.getPaddingLeft() - v.getPaddingRight();
- if (mChooserMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
- gridAdapter.calculateChooserTargetWidth(availableWidth);
- return;
- }
-
- if (gridAdapter.consumeLayoutRequest()
+ boolean isLayoutUpdated = gridAdapter.consumeLayoutRequest()
|| gridAdapter.calculateChooserTargetWidth(availableWidth)
|| recyclerView.getAdapter() == null
- || mLastNumberOfChildren != recyclerView.getChildCount()
- || availableWidth != mCurrAvailableWidth) {
+ || availableWidth != mCurrAvailableWidth;
+ if (isLayoutUpdated
+ || mLastNumberOfChildren != recyclerView.getChildCount()) {
mCurrAvailableWidth = availableWidth;
+ if (isLayoutUpdated
+ && mChooserMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
+ // This fixes b/150936654 - empty work tab in share sheet when swiping
+ mChooserMultiProfilePagerAdapter.getActiveAdapterView()
+ .setAdapter(mChooserMultiProfilePagerAdapter.getCurrentRootAdapter());
+ return;
+ } else if (mChooserMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
+ return;
+ }
getMainThreadHandler().post(() -> {
if (mResolverDrawerLayout == null || gridAdapter == null) {
@@ -2452,39 +2457,46 @@
offset += tabDivider.getHeight();
}
- int directShareHeight = 0;
- rowsToShow = Math.min(4, rowsToShow);
- mLastNumberOfChildren = recyclerView.getChildCount();
- for (int i = 0, childCount = recyclerView.getChildCount();
- i < childCount && rowsToShow > 0; i++) {
- View child = recyclerView.getChildAt(i);
- if (((GridLayoutManager.LayoutParams)
- child.getLayoutParams()).getSpanIndex() != 0) {
- continue;
+ if (recyclerView.getVisibility() == View.VISIBLE) {
+ int directShareHeight = 0;
+ rowsToShow = Math.min(4, rowsToShow);
+ mLastNumberOfChildren = recyclerView.getChildCount();
+ for (int i = 0, childCount = recyclerView.getChildCount();
+ i < childCount && rowsToShow > 0; i++) {
+ View child = recyclerView.getChildAt(i);
+ if (((GridLayoutManager.LayoutParams)
+ child.getLayoutParams()).getSpanIndex() != 0) {
+ continue;
+ }
+ int height = child.getHeight();
+ offset += height;
+
+ if (gridAdapter.getTargetType(
+ recyclerView.getChildAdapterPosition(child))
+ == ChooserListAdapter.TARGET_SERVICE) {
+ directShareHeight = height;
+ }
+ rowsToShow--;
}
- int height = child.getHeight();
- offset += height;
- if (gridAdapter.getTargetType(
- recyclerView.getChildAdapterPosition(child))
- == ChooserListAdapter.TARGET_SERVICE) {
- directShareHeight = height;
+ boolean isExpandable = getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT && !isInMultiWindowMode();
+ if (directShareHeight != 0 && isSendAction(getTargetIntent())
+ && isExpandable) {
+ // make sure to leave room for direct share 4->8 expansion
+ int requiredExpansionHeight =
+ (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
+ int topInset = mSystemWindowInsets != null ? mSystemWindowInsets.top : 0;
+ int minHeight = bottom - top - mResolverDrawerLayout.getAlwaysShowHeight()
+ - requiredExpansionHeight - topInset - bottomInset;
+
+ offset = Math.min(offset, minHeight);
}
- rowsToShow--;
- }
-
- boolean isExpandable = getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_PORTRAIT && !isInMultiWindowMode();
- if (directShareHeight != 0 && isSendAction(getTargetIntent())
- && isExpandable) {
- // make sure to leave room for direct share 4->8 expansion
- int requiredExpansionHeight =
- (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
- int topInset = mSystemWindowInsets != null ? mSystemWindowInsets.top : 0;
- int minHeight = bottom - top - mResolverDrawerLayout.getAlwaysShowHeight()
- - requiredExpansionHeight - topInset - bottomInset;
-
- offset = Math.min(offset, minHeight);
+ } else {
+ ViewGroup currentEmptyStateView = getCurrentEmptyStateView();
+ if (currentEmptyStateView.getVisibility() == View.VISIBLE) {
+ offset += currentEmptyStateView.getHeight();
+ }
}
mResolverDrawerLayout.setCollapsibleHeightReserved(Math.min(offset, bottom - top));
@@ -2492,6 +2504,11 @@
}
}
+ private ViewGroup getCurrentEmptyStateView() {
+ int currentPage = mChooserMultiProfilePagerAdapter.getCurrentPage();
+ return mChooserMultiProfilePagerAdapter.getItem(currentPage).getEmptyStateView();
+ }
+
static class BaseChooserTargetComparator implements Comparator<ChooserTarget> {
@Override
public int compare(ChooserTarget lhs, ChooserTarget rhs) {
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 4c203d3..523ed6f 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -164,6 +164,30 @@
boolean clearOverride(long changeId, String packageName);
/**
+ * Enable all compatibility changes which have enabledAfterTargetSdk ==
+ * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
+ * changes to take effect.
+ *
+ * @param packageName The package name of the app whose compatibility changes will be enabled.
+ * @param targetSdkVersion The targetSdkVersion for filtering the changes to be enabled.
+ *
+ * @return The number of changes that were enabled.
+ */
+ int enableTargetSdkChanges(in String packageName, int targetSdkVersion);
+
+ /**
+ * Disable all compatibility changes which have enabledAfterTargetSdk ==
+ * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
+ * changes to take effect.
+ *
+ * @param packageName The package name of the app whose compatibility changes will be disabled.
+ * @param targetSdkVersion The targetSdkVersion for filtering the changes to be disabled.
+ *
+ * @return The number of changes that were disabled.
+ */
+ int disableTargetSdkChanges(in String packageName, int targetSdkVersion);
+
+ /**
* Revert overrides to compatibility changes. Kills the app to allow the changes to take effect.
*
* @param packageName The package name of the app whose overrides will be cleared.
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 73ef8c6..2f048c9 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -430,7 +430,7 @@
if (shouldHide(file)) continue;
if (file.isDirectory()) {
- for (File child : file.listFiles()) {
+ for (File child : FileUtils.listFilesOrEmpty(file)) {
pending.add(child);
}
}
diff --git a/core/java/com/android/internal/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java
index 85643fc..c90d8512 100644
--- a/core/java/com/android/internal/logging/InstanceId.java
+++ b/core/java/com/android/internal/logging/InstanceId.java
@@ -48,6 +48,17 @@
return mId;
}
+ /**
+ * Create a fake instance ID for testing purposes. Not for production use. See also
+ * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence.
+ * @param id The ID you want to assign.
+ * @return new InstanceId.
+ */
+ @VisibleForTesting
+ public static InstanceId fakeInstanceId(int id) {
+ return new InstanceId(id);
+ }
+
@Override
public int hashCode() {
return mId;
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index 91ef0b5..1296ddc 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -116,6 +116,7 @@
NETWORK_STATUS,
context.getString(R.string.notification_channel_network_status),
NotificationManager.IMPORTANCE_LOW);
+ network.setBlockableSystem(true);
channelsList.add(network);
final NotificationChannel networkAlertsChannel = new NotificationChannel(
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
index f8c0d9e..fdcc8a8 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
@@ -29,6 +29,7 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Matcher;
@@ -99,7 +100,7 @@
}
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
updateReader();
}
diff --git a/core/java/com/android/internal/util/NotificationMessagingUtil.java b/core/java/com/android/internal/util/NotificationMessagingUtil.java
index bf796cd..28994fd 100644
--- a/core/java/com/android/internal/util/NotificationMessagingUtil.java
+++ b/core/java/com/android/internal/util/NotificationMessagingUtil.java
@@ -28,6 +28,7 @@
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
+import java.util.Collection;
import java.util.Objects;
/**
@@ -77,8 +78,8 @@
private final ContentObserver mSmsContentObserver = new ContentObserver(
new Handler(Looper.getMainLooper())) {
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- if (Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING).equals(uri)) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
+ if (uris.contains(Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING))) {
cacheDefaultSmsApp(userId);
}
}
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 5dd3389b..47f094f 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -116,7 +116,8 @@
}
@Override
- public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync) {
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom,
+ boolean sync) {
if (sync) {
try {
mSession.wallpaperOffsetsComplete(asBinder());
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index 3378c07..d40924b 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -82,6 +82,9 @@
// property for runtime configuration differentiation
private static final String SKU_PROPERTY = "ro.boot.product.hardware.sku";
+ // property for runtime configuration differentiation in vendor
+ private static final String VENDOR_SKU_PROPERTY = "ro.boot.product.vendor.sku";
+
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
int[] mGlobalGids;
@@ -468,6 +471,17 @@
readPermissions(Environment.buildPath(
Environment.getVendorDirectory(), "etc", "permissions"), vendorPermissionFlag);
+ String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, "");
+ if (!vendorSkuProperty.isEmpty()) {
+ String vendorSkuDir = "sku_" + vendorSkuProperty;
+ readPermissions(Environment.buildPath(
+ Environment.getVendorDirectory(), "etc", "sysconfig", vendorSkuDir),
+ vendorPermissionFlag);
+ readPermissions(Environment.buildPath(
+ Environment.getVendorDirectory(), "etc", "permissions", vendorSkuDir),
+ vendorPermissionFlag);
+ }
+
// Allow ODM to customize system configs as much as Vendor, because /odm is another
// vendor partition other than /vendor.
int odmPermissionFlag = vendorPermissionFlag;
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 0d0dc3e..f7c6dbd 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -853,8 +853,11 @@
} cfg_state = CONFIG_UNKNOWN;
if (cfg_state == CONFIG_UNKNOWN) {
- const std::map<std::string, std::string> configs =
- vintf::VintfObject::GetInstance()->getRuntimeInfo()->kernelConfigs();
+ auto runtime_info = vintf::VintfObject::GetInstance()
+ ->getRuntimeInfo(false /* skip cache */,
+ vintf::RuntimeInfo::FetchFlag::CONFIG_GZ);
+ CHECK(runtime_info != nullptr) << "Kernel configs cannot be fetched. b/151092221";
+ const std::map<std::string, std::string>& configs = runtime_info->kernelConfigs();
std::map<std::string, std::string>::const_iterator it = configs.find("CONFIG_VMAP_STACK");
cfg_state = (it != configs.end() && it->second == "y") ? CONFIG_SET : CONFIG_UNSET;
}
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index 4777169..f14e3ed 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -20,6 +20,43 @@
option java_outer_classname = "TelephonyProtoEnums";
option java_multiple_files = true;
+enum CallBearerEnum {
+ /** Call bearer is unknown or invalid */
+ CALL_BEARER_UNKNOWN = 0;
+
+ /** Call bearer is legacy CS */
+ CALL_BEARER_CS = 1;
+
+ /** Call bearer is IMS */
+ CALL_BEARER_IMS = 2;
+}
+
+enum CallDirectionEnum {
+ /** Call direction: unknown or invalid */
+ CALL_DIRECTION_UNKNOWN = 0;
+
+ /** Call direction: mobile originated (outgoing for this device) */
+ CALL_DIRECTION_MO = 1;
+
+ /** Call direction: mobile terminated (incoming for this device) */
+ CALL_DIRECTION_MT = 2;
+}
+
+// Call setup duration buckets.
+// See com.android.internal.telephony.metrics.VoiceCallSessionStats for definition.
+enum CallSetupDurationEnum {
+ CALL_SETUP_DURATION_UNKNOWN = 0;
+ CALL_SETUP_DURATION_EXTREMELY_FAST = 1;
+ CALL_SETUP_DURATION_ULTRA_FAST = 2;
+ CALL_SETUP_DURATION_VERY_FAST = 3;
+ CALL_SETUP_DURATION_FAST = 4;
+ CALL_SETUP_DURATION_NORMAL = 5;
+ CALL_SETUP_DURATION_SLOW = 6;
+ CALL_SETUP_DURATION_VERY_SLOW = 7;
+ CALL_SETUP_DURATION_ULTRA_SLOW = 8;
+ CALL_SETUP_DURATION_EXTREMELY_SLOW = 9;
+}
+
// Data conn. power states, primarily used by android/telephony/DataConnectionRealTimeInfo.java.
enum DataConnectionPowerStateEnum {
DATA_CONNECTION_POWER_STATE_LOW = 1;
@@ -63,7 +100,6 @@
SIGNAL_STRENGTH_GREAT = 4;
}
-
enum ServiceStateEnum {
/**
* Normal operation condition, the phone is registered
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8851170..0dd3ad6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1187,6 +1187,16 @@
android:description="@string/permdesc_callCompanionApp"
android:protectionLevel="normal" />
+ <!-- Exempt this uid from restrictions to background audio recoding
+ <p>Protection level: signature|privileged
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS"
+ android:label="@string/permlab_exemptFromAudioRecordRestrictions"
+ android:description="@string/permdesc_exemptFromAudioRecordRestrictions"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows a calling app to continue a call which was started in another app. An example is a
video calling app that wants to continue a voice call on the user's mobile network.<p>
When the handover of a call from one app to another takes place, there are two devices
@@ -1305,7 +1315,7 @@
android:description="@string/permdesc_camera"
android:protectionLevel="dangerous|instant" />
- <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
+ <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
system only camera devices.
<p>Protection level: system|signature
@hide -->
@@ -1315,6 +1325,15 @@
android:description="@string/permdesc_systemCamera"
android:protectionLevel="system|signature" />
+ <!-- Allows receiving the camera service notifications when a camera is opened
+ (by a certain application package) or closed.
+ @hide -->
+ <permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_cameraOpenCloseListener"
+ android:description="@string/permdesc_cameraOpenCloseListener"
+ android:protectionLevel="signature" />
+
<!-- ====================================================================== -->
<!-- Permissions for accessing the device sensors -->
<!-- ====================================================================== -->
@@ -3726,7 +3745,8 @@
<permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"
android:protectionLevel="signature|installer" />
- <!-- @hide Allows an application to upgrade runtime permissions. -->
+ <!-- @SystemApi @TestApi Allows an application to upgrade runtime permissions.
+ @hide -->
<permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS"
android:protectionLevel="signature" />
diff --git a/core/res/res/layout-car/car_resolver_different_item_header.xml b/core/res/res/layout-car/car_resolver_different_item_header.xml
deleted file mode 100644
index 222ecc6..0000000
--- a/core/res/res/layout-car/car_resolver_different_item_header.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alwaysShow="true"
- android:text="@*android:string/use_a_different_app"
- android:minHeight="56dp"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:gravity="start|center_vertical"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:elevation="8dp"
-/>
\ No newline at end of file
diff --git a/core/res/res/layout-car/car_resolver_list.xml b/core/res/res/layout-car/car_resolver_list.xml
index 15a8645..755cbfe 100644
--- a/core/res/res/layout-car/car_resolver_list.xml
+++ b/core/res/res/layout-car/car_resolver_list.xml
@@ -23,90 +23,142 @@
android:id="@id/contentPanel">
<LinearLayout
- android:id="@+id/button_bar"
- android:visibility="gone"
- style="?attr/buttonBarStyle"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_ignoreOffset="true"
- android:layout_alwaysShow="true"
- android:layout_hasNestedScrollIndicator="true"
- android:background="?attr/colorBackgroundFloating"
- android:orientation="horizontal"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="12dp"
+ android:layout_height="match_parent"
android:weightSum="5"
- android:paddingEnd="12dp"
+ android:layout_alwaysShow="true"
+ android:orientation="vertical"
+ android:background="?attr/colorBackgroundFloating"
android:elevation="8dp">
- <TextView
- android:id="@+id/profile_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:textSize="40sp"
- android:layout_weight="5"
- android:layout_gravity = "left"
+ <LinearLayout
+ android:id="@+id/button_bar"
android:visibility="gone"
- android:textColor="?attr/colorAccent"
- android:singleLine="true"/>
-
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
+ style="?attr/buttonBarStyle"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="56dp"
- android:layout_gravity = "left"
- android:layout_weight="3"
+ android:layout_ignoreOffset="true"
+ android:layout_alwaysShow="true"
+ android:layout_hasNestedScrollIndicator="true"
+ android:background="?attr/colorBackgroundFloating"
+ android:orientation="horizontal"
android:paddingTop="8dp"
- android:layout_below="@id/profile_button"
- android:paddingBottom="8dp"/>
+ android:paddingStart="12dp"
+ android:weightSum="4"
+ android:paddingEnd="12dp"
+ android:elevation="8dp">
- <Button
- android:id="@+id/button_once"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:layout_gravity = "right"
- android:text="@string/activity_resolver_use_once"
- android:layout_weight="1"
- android:onClick="onButtonClick"/>
+ <TextView
+ android:id="@+id/profile_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:textSize="40sp"
+ android:layout_weight="4"
+ android:layout_gravity="left"
+ android:visibility="gone"
+ android:textColor="?attr/colorAccent"
+ android:singleLine="true"/>
- <Button
- android:id="@+id/button_always"
- android:layout_marginLeft="10dp"
- android:layout_width="wrap_content"
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:layout_weight="3"
+ android:paddingTop="8dp"
+ android:layout_below="@id/profile_button"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:paddingBottom="8dp"/>
+
+ <Button
+ android:id="@+id/button_once"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:layout_gravity="right"
+ style="?attr/buttonBarButtonStyle"
+ android:text="@string/activity_resolver_use_once"
+ android:layout_weight="0.5"
+ android:onClick="onButtonClick"/>
+
+ <Button
+ android:id="@+id/button_always"
+ android:layout_marginLeft="2dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:layout_gravity="right"
+ style="?attr/buttonBarButtonStyle"
+ android:text="@string/activity_resolver_use_always"
+ android:layout_weight="0.5"
+ android:onClick="onButtonClick"/>
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/stub"
+ android:visibility="gone"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:enabled="false"
- android:layout_gravity = "right"
- android:text="@string/activity_resolver_use_always"
- android:layout_weight="1"
- android:onClick="onButtonClick"/>
+ android:background="?attr/colorBackgroundFloating"/>
+
+ <TabHost
+ android:id="@+id/profile_tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/colorBackgroundFloating">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ </TabWidget>
+ <View
+ android:id="@+id/resolver_tab_divider"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/colorBackgroundFloating"
+ android:foreground="?attr/dividerVertical"
+ android:layout_marginBottom="8dp"/>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <com.android.internal.app.ResolverViewPager
+ android:id="@+id/profile_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+
+ <View
+ android:layout_alwaysShow="true"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/colorBackgroundFloating"
+ android:foreground="?attr/dividerVertical"/>
+
+ <TextView android:id="@+id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/colorBackgroundFloating"
+ android:elevation="8dp"
+ android:layout_alwaysShow="true"
+ android:text="@string/noApplications"
+ android:padding="32dp"
+ android:gravity="center"
+ android:visibility="gone"/>
+
</LinearLayout>
- <ListView
- android:layout_width="match_parent"
- android:layout_height="500dp"
- android:id="@+id/resolver_list"
- android:clipToPadding="false"
- android:scrollbarStyle="outsideOverlay"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="8dp"
- android:nestedScrollingEnabled="true"
- android:scrollIndicators="top|bottom"/>
-
- <TextView android:id="@+id/empty"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="8dp"
- android:layout_alwaysShow="true"
- android:text="@string/noApplications"
- android:padding="32dp"
- android:gravity="center"
- android:visibility="gone"/>
-
</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout-car/car_resolver_list_with_default.xml b/core/res/res/layout-car/car_resolver_list_with_default.xml
index 2aed00b..5e450b2 100644
--- a/core/res/res/layout-car/car_resolver_list_with_default.xml
+++ b/core/res/res/layout-car/car_resolver_list_with_default.xml
@@ -40,12 +40,12 @@
<ImageView
android:id="@+id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="60dp"
+ android:layout_height="60dp"
android:layout_gravity="start|top"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginTop="20dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="5dp"
+ android:layout_marginTop="10dp"
android:src="@drawable/resolver_icon_placeholder"
android:scaleType="fitCenter"/>
@@ -55,7 +55,7 @@
android:layout_weight="1"
android:layout_height="?attr/listPreferredItemHeight"
android:layout_marginStart="16dp"
- android:textAppearance="?attr/textAppearanceMedium"
+ android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="start|center_vertical"
android:paddingEnd="16dp"/>
@@ -120,7 +120,7 @@
android:layout_width="wrap_content"
android:layout_gravity="start"
android:maxLines="2"
- style="?attr/buttonBarNegativeButtonStyle"
+ style="?attr/buttonBarButtonStyle"
android:minHeight="@dimen/alert_dialog_button_bar_height"
android:layout_height="wrap_content"
android:enabled="false"
@@ -133,29 +133,64 @@
android:layout_gravity="end"
android:maxLines="2"
android:minHeight="@dimen/alert_dialog_button_bar_height"
- style="?attr/buttonBarPositiveButtonStyle"
+ style="?attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:enabled="false"
android:text="@string/activity_resolver_use_always"
android:onClick="onButtonClick"/>
</LinearLayout>
+ <FrameLayout
+ android:id="@+id/stub"
+ android:layout_alwaysShow="true"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/colorBackgroundFloating"/>
+
+ <TabHost
+ android:layout_alwaysShow="true"
+ android:id="@+id/profile_tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/colorBackgroundFloating">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ </TabWidget>
+ <View
+ android:id="@+id/resolver_tab_divider"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/colorBackgroundFloating"
+ android:foreground="?attr/dividerVertical"
+ android:layout_marginBottom="8dp"/>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <com.android.internal.app.ResolverViewPager
+ android:id="@+id/profile_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ </com.android.internal.app.ResolverViewPager>
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dividerVertical"/>
-
- <ListView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/resolver_list"
- android:layout_weight="4"
- android:clipToPadding="false"
- android:scrollbarStyle="outsideOverlay"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="8dp"
- android:nestedScrollingEnabled="true"
- android:divider="@null"/>
</LinearLayout>
</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index e17fc8a..b754e0c 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -100,8 +100,7 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
- android:foreground="?attr/dividerVertical"
- android:layout_marginBottom="@dimen/resolver_tab_divider_bottom_padding"/>
+ android:foreground="?attr/dividerVertical"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 0d4523a..06a7633 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -183,8 +183,7 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
- android:foreground="?attr/dividerVertical"
- android:layout_marginBottom="@dimen/resolver_tab_divider_bottom_padding"/>
+ android:foreground="?attr/dividerVertical"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
diff --git a/core/res/res/values-mcc219/config.xml b/core/res/res/values-mcc219/config.xml
deleted file mode 100644
index 7ae82fa..0000000
--- a/core/res/res/values-mcc219/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array name="config_twoDigitNumberPattern">
- <item>"92"</item>
- <item>"93"</item>
- <item>"94"</item>
- <item>"95"</item>
- <item>"96"</item>
- </string-array>
-
-</resources>
diff --git a/core/res/res/values-mcc220/config.xml b/core/res/res/values-mcc220/config.xml
deleted file mode 100644
index 7ae82fa..0000000
--- a/core/res/res/values-mcc220/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array name="config_twoDigitNumberPattern">
- <item>"92"</item>
- <item>"93"</item>
- <item>"94"</item>
- <item>"95"</item>
- <item>"96"</item>
- </string-array>
-
-</resources>
diff --git a/core/res/res/values-mcc310-mnc150/config.xml b/core/res/res/values-mcc310-mnc150/config.xml
deleted file mode 100644
index e7d1325..0000000
--- a/core/res/res/values-mcc310-mnc150/config.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"0"</item>
- <item>"00"</item>
- <item>"*0"</item>
- <item>"*1"</item>
- <item>"*2"</item>
- <item>"*3"</item>
- <item>"*4"</item>
- <item>"*5"</item>
- <item>"*6"</item>
- <item>"*7"</item>
- <item>"*8"</item>
- <item>"*9"</item>
- <item>"#0"</item>
- <item>"#1"</item>
- <item>"#2"</item>
- <item>"#3"</item>
- <item>"#4"</item>
- <item>"#5"</item>
- <item>"#6"</item>
- <item>"#7"</item>
- <item>"#8"</item>
- <item>"#9"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml
index 3fb3f0f..53e4193 100644
--- a/core/res/res/values-mcc310-mnc410/config.xml
+++ b/core/res/res/values-mcc310-mnc410/config.xml
@@ -23,31 +23,6 @@
<!-- Configure mobile network MTU. Carrier specific value is set here.
-->
<integer name="config_mobile_mtu">1410</integer>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array name="config_twoDigitNumberPattern">
- <item>"0"</item>
- <item>"00"</item>
- <item>"*0"</item>
- <item>"*1"</item>
- <item>"*2"</item>
- <item>"*3"</item>
- <item>"*4"</item>
- <item>"*5"</item>
- <item>"*6"</item>
- <item>"*7"</item>
- <item>"*8"</item>
- <item>"*9"</item>
- <item>"#0"</item>
- <item>"#1"</item>
- <item>"#2"</item>
- <item>"#3"</item>
- <item>"#4"</item>
- <item>"#5"</item>
- <item>"#6"</item>
- <item>"#7"</item>
- <item>"#8"</item>
- <item>"#9"</item>
- </string-array>
<!-- Enable 5 bar signal strength icon -->
<bool name="config_inflateSignalStrength">true</bool>
diff --git a/core/res/res/values-mcc313-mnc100/config.xml b/core/res/res/values-mcc313-mnc100/config.xml
deleted file mode 100644
index ccd03f1..0000000
--- a/core/res/res/values-mcc313-mnc100/config.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2019, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"0"</item>
- <item>"00"</item>
- <item>"*0"</item>
- <item>"*1"</item>
- <item>"*2"</item>
- <item>"*3"</item>
- <item>"*4"</item>
- <item>"*5"</item>
- <item>"*6"</item>
- <item>"*7"</item>
- <item>"*8"</item>
- <item>"*9"</item>
- <item>"#0"</item>
- <item>"#1"</item>
- <item>"#2"</item>
- <item>"#3"</item>
- <item>"#4"</item>
- <item>"#5"</item>
- <item>"#6"</item>
- <item>"#7"</item>
- <item>"#8"</item>
- <item>"#9"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc334-mnc050/config.xml b/core/res/res/values-mcc334-mnc050/config.xml
index 23678f1..2e8c504 100644
--- a/core/res/res/values-mcc334-mnc050/config.xml
+++ b/core/res/res/values-mcc334-mnc050/config.xml
@@ -31,8 +31,4 @@
<item>9</item>
</integer-array>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"#9"</item>
- </string-array>
</resources>
diff --git a/core/res/res/values-mcc334-mnc090/config.xml b/core/res/res/values-mcc334-mnc090/config.xml
deleted file mode 100644
index 1632a42..0000000
--- a/core/res/res/values-mcc334-mnc090/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2017, 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
-
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"#9"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc704-mnc01/config.xml b/core/res/res/values-mcc704-mnc01/config.xml
deleted file mode 100644
index 10b6470..0000000
--- a/core/res/res/values-mcc704-mnc01/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, 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 my 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.
-*/
--->
-
-<resources>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array name="config_twoDigitNumberPattern">
- <item>"*1"</item>
- <item>"*5"</item>
- <item>"*9"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc708-mnc001/config.xml b/core/res/res/values-mcc708-mnc001/config.xml
deleted file mode 100755
index 7b7c48d..0000000
--- a/core/res/res/values-mcc708-mnc001/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources>
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"*1"</item>
- <item>"*5"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0b6e65fe..6f468e0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2024,7 +2024,10 @@
a keyboard is present. -->
<bool name="config_showMenuShortcutsWhenKeyboardPresent">false</bool>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD.
+
+ Note: This config is deprecated, please use carrier config which is
+ CarrierConfigManager.KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY instead. -->
<string-array name="config_twoDigitNumberPattern" translatable="false">
</string-array>
@@ -4415,4 +4418,7 @@
<!-- Package name of custom session policy provider class used by MediaSessionService. -->
<string name="config_customSessionPolicyProvider"></string>
+
+ <!-- The max scale for the wallpaper when it's zoomed in -->
+ <item name="config_wallpaperMaxScale" format="float" type="dimen">1</item>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 9118617..2faa0c9 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -776,7 +776,6 @@
<dimen name="resolver_empty_state_height_with_tabs">268dp</dimen>
<dimen name="resolver_max_collapsed_height">192dp</dimen>
<dimen name="resolver_max_collapsed_height_with_tabs">248dp</dimen>
- <dimen name="resolver_tab_divider_bottom_padding">8dp</dimen>
<dimen name="chooser_action_button_icon_size">18dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d30fdce..789628d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1166,6 +1166,11 @@
<!-- 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_systemCamera">This privileged | system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well</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_cameraOpenCloseListener">Allow an application or service to receive callbacks about camera devices being opened or closed.</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_cameraOpenCloseListener">This signature app can receive callbacks when any camera device is being opened (by what application package) or closed.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_vibrate">control vibration</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -1212,6 +1217,14 @@
device. This includes information such as call numbers for calls and the state of the
calls.</string>
+ <!-- Title of an application permission. When granted the app is exempt from audio record
+ restrictions.
+ [CHAR LIMIT=NONE]-->
+ <string name="permlab_exemptFromAudioRecordRestrictions">exempt from audio record restrictions</string>
+ <!-- Description of an application permission. When granted the app is exempt from audio record
+ restrictions. [CHAR LIMIT=NONE]-->
+ <string name="permdesc_exemptFromAudioRecordRestrictions">Exempt the app from restrictions to record audio.</string>
+
<!-- Title of an application permission. When granted the user is giving access to a third
party app to continue a call which originated in another app. For example, the user
could be in a voice call over their carrier's mobile network, and a third party video
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 826379d..a9008d7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3909,7 +3909,6 @@
<java-symbol type="dimen" name="resolver_empty_state_height_with_tabs" />
<java-symbol type="dimen" name="resolver_max_collapsed_height_with_tabs" />
<java-symbol type="bool" name="sharesheet_show_content_preview" />
- <java-symbol type="dimen" name="resolver_tab_divider_bottom_padding" />
<!-- Toast message for background started foreground service while-in-use permission restriction feature -->
<java-symbol type="string" name="allow_while_in_use_permission_in_fgs" />
@@ -3927,4 +3926,6 @@
<java-symbol type="string" name="config_customMediaKeyDispatcher" />
<java-symbol type="string" name="config_customSessionPolicyProvider" />
+ <!-- The max scale for the wallpaper when it's zoomed in -->
+ <java-symbol type="dimen" name="config_wallpaperMaxScale"/>
</resources>
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
index c307e64..328429c 100644
--- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -39,6 +39,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -194,8 +195,8 @@
}
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- if (mExpectedUri.equals(uri) && mExpectedUserId == userId) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
+ if (uris.contains(mExpectedUri) && mExpectedUserId == userId) {
mLatch.countDown();
}
}
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index d98ceaf..c0325ca 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -23,7 +23,10 @@
import static android.os.Environment.classifyExternalStorageDirectory;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import android.app.AppOpsManager;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
@@ -40,10 +43,33 @@
public class EnvironmentTest {
private File dir;
- private Context getContext() {
+ private static Context getContext() {
return InstrumentationRegistry.getContext();
}
+ /**
+ * Sets {@code mode} for the given {@code ops} and the given {@code uid}.
+ *
+ * <p>This method drops shell permission identity.
+ */
+ private static void setAppOpsModeForUid(int uid, int mode, String... ops) {
+ if (ops == null) {
+ return;
+ }
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity();
+ try {
+ for (String op : ops) {
+ getContext().getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
+ }
+ } finally {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
@Before
public void setUp() throws Exception {
dir = getContext().getDir("testing", Context.MODE_PRIVATE);
@@ -101,4 +127,17 @@
Environment.buildPath(dir, "Taxes.pdf").createNewFile();
assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir));
}
+
+ @Test
+ public void testIsExternalStorageManager() throws Exception {
+ assertFalse(Environment.isExternalStorageManager());
+ try {
+ setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
+ assertTrue(Environment.isExternalStorageManager());
+ } finally {
+ setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_DEFAULT,
+ AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 7737b1a..023fc17 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -49,6 +49,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type;
+import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
import android.view.WindowManager.BadTokenException;
import android.view.WindowManager.LayoutParams;
import android.view.animation.LinearInterpolator;
@@ -67,6 +68,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
import java.util.concurrent.CountDownLatch;
import java.util.function.Supplier;
@@ -171,15 +174,24 @@
mController.onControlsChanged(new InsetsSourceControl[] { control });
assertEquals(mLeash,
mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl().getLeash());
+ mController.addOnControllableInsetsChangedListener(
+ ((controller, typeMask) -> assertEquals(statusBars(), typeMask)));
}
@Test
public void testControlsRevoked() {
+ OnControllableInsetsChangedListener listener
+ = mock(OnControllableInsetsChangedListener.class);
+ mController.addOnControllableInsetsChangedListener(listener);
InsetsSourceControl control =
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
mController.onControlsChanged(new InsetsSourceControl[] { control });
mController.onControlsChanged(new InsetsSourceControl[0]);
assertNull(mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl());
+ InOrder inOrder = Mockito.inOrder(listener);
+ inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(0));
+ inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(statusBars()));
+ inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(0));
}
@Test
@@ -206,10 +218,15 @@
public void testFrameDoesntMatchDisplay() {
mController.onFrameChanged(new Rect(0, 0, 100, 100));
mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200));
+ InsetsSourceControl control =
+ new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
+ mController.onControlsChanged(new InsetsSourceControl[] { control });
WindowInsetsAnimationControlListener controlListener =
mock(WindowInsetsAnimationControlListener.class);
mController.controlWindowInsetsAnimation(0, 0 /* durationMs */, new LinearInterpolator(),
controlListener);
+ mController.addOnControllableInsetsChangedListener(
+ (controller, typeMask) -> assertEquals(0, typeMask));
verify(controlListener).onCancelled();
verify(controlListener, never()).onReady(any(), anyInt());
}
diff --git a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
index 9787b77..9797178 100644
--- a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
@@ -25,12 +25,14 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.os.CancellationSignal;
import android.platform.test.annotations.Presubmit;
+import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
import android.view.animation.LinearInterpolator;
import org.junit.Before;
@@ -163,11 +165,43 @@
}
@Test
+ public void testAddOnControllableInsetsChangedListener() {
+ OnControllableInsetsChangedListener listener =
+ mock(OnControllableInsetsChangedListener.class);
+ mPendingInsetsController.addOnControllableInsetsChangedListener(listener);
+ mPendingInsetsController.replayAndAttach(mReplayedController);
+ verify(mReplayedController).addOnControllableInsetsChangedListener(eq(listener));
+ verify(listener).onControllableInsetsChanged(eq(mPendingInsetsController), eq(0));
+ }
+
+ @Test
+ public void testAddRemoveControllableInsetsChangedListener() {
+ OnControllableInsetsChangedListener listener =
+ mock(OnControllableInsetsChangedListener.class);
+ mPendingInsetsController.addOnControllableInsetsChangedListener(listener);
+ mPendingInsetsController.removeOnControllableInsetsChangedListener(listener);
+ mPendingInsetsController.replayAndAttach(mReplayedController);
+ verify(mReplayedController, never()).addOnControllableInsetsChangedListener(any());
+ verify(listener).onControllableInsetsChanged(eq(mPendingInsetsController), eq(0));
+ }
+
+ @Test
+ public void testAddOnControllableInsetsChangedListener_direct() {
+ mPendingInsetsController.replayAndAttach(mReplayedController);
+ OnControllableInsetsChangedListener listener =
+ mock(OnControllableInsetsChangedListener.class);
+ mPendingInsetsController.addOnControllableInsetsChangedListener(listener);
+ verify(mReplayedController).addOnControllableInsetsChangedListener(eq(listener));
+ }
+
+ @Test
public void testReplayTwice() {
mPendingInsetsController.show(systemBars());
mPendingInsetsController.setSystemBarsBehavior(BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
mPendingInsetsController.setSystemBarsAppearance(APPEARANCE_LIGHT_STATUS_BARS,
APPEARANCE_LIGHT_STATUS_BARS);
+ mPendingInsetsController.addOnControllableInsetsChangedListener(
+ (controller, typeMask) -> {});
mPendingInsetsController.replayAndAttach(mReplayedController);
InsetsController secondController = mock(InsetsController.class);
mPendingInsetsController.replayAndAttach(secondController);
diff --git a/data/etc/com.android.documentsui.xml b/data/etc/com.android.documentsui.xml
index b6671db..1e570ba 100644
--- a/data/etc/com.android.documentsui.xml
+++ b/data/etc/com.android.documentsui.xml
@@ -20,6 +20,7 @@
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<!-- Permissions required for reading and logging compat changes -->
<permission name="android.permission.LOG_COMPAT_CHANGE"/>
+ <permission name="android.permission.MODIFY_QUIET_MODE"/>
<permission name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 38e18a9..72827a9 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -63,5 +63,6 @@
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/>
<permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+ <permission name="android.permission.CAMERA_OPEN_CLOSE_LISTENER" />
</privapp-permissions>
</permissions>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 49edcf7..487a6e9 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -164,6 +164,7 @@
<permission name="android.permission.REBOOT"/>
<permission name="android.permission.REGISTER_CALL_PROVIDER"/>
<permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
+ <permission name="android.permission.REGISTER_STATS_PULL_ATOM"/>
<permission name="android.permission.SEND_RESPOND_VIA_MESSAGE"/>
<permission name="android.permission.SET_TIME_ZONE"/>
<permission name="android.permission.SHUTDOWN"/>
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index d9d2eea..a7d0cb8 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -764,8 +764,9 @@
private @KeyProperties.BlockModeEnum String[] mBlockModes;
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
- private int mUserAuthenticationValidityDurationSeconds = -1;
- private @KeyProperties.AuthEnum int mUserAuthenticationType;
+ private int mUserAuthenticationValidityDurationSeconds = 0;
+ private @KeyProperties.AuthEnum int mUserAuthenticationType =
+ KeyProperties.AUTH_BIOMETRIC_STRONG;
private boolean mUserPresenceRequired = false;
private byte[] mAttestationChallenge = null;
private boolean mUniqueIdIncluded = false;
@@ -1240,7 +1241,8 @@
if (seconds == -1) {
return setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG);
}
- return setUserAuthenticationParameters(seconds, KeyProperties.AUTH_BIOMETRIC_STRONG);
+ return setUserAuthenticationParameters(seconds, KeyProperties.AUTH_DEVICE_CREDENTIAL
+ | KeyProperties.AUTH_BIOMETRIC_STRONG);
}
/**
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 8120a93..2e793de 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -562,8 +562,9 @@
private @KeyProperties.BlockModeEnum String[] mBlockModes;
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
- private @KeyProperties.AuthEnum int mUserAuthenticationType;
- private int mUserAuthenticationValidityDurationSeconds = -1;
+ private int mUserAuthenticationValidityDurationSeconds = 0;
+ private @KeyProperties.AuthEnum int mUserAuthenticationType =
+ KeyProperties.AUTH_BIOMETRIC_STRONG;
private boolean mUserPresenceRequired = false;
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
@@ -870,7 +871,8 @@
if (seconds == -1) {
return setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG);
}
- return setUserAuthenticationParameters(seconds, KeyProperties.AUTH_BIOMETRIC_STRONG);
+ return setUserAuthenticationParameters(seconds, KeyProperties.AUTH_DEVICE_CREDENTIAL
+ | KeyProperties.AUTH_BIOMETRIC_STRONG);
}
/**
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 4ead253..bc933ff 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -165,8 +165,7 @@
}
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
KeymasterArguments.toUint64(sid));
- args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
- KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_BIOMETRIC);
+ args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
spec.getUserAuthenticationValidityDurationSeconds());
if (spec.isUserAuthenticationValidWhileOnBody()) {
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 84c07d7..39900e6 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -146,12 +146,11 @@
}
Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc);
- bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) &&
- MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
- layer.setForceFilter(!disableFilter);
layer.setSize(displayedWidth, displayedHeight);
texTransform.copyTo(layer.getTexTransform());
layer.setImage(image);
+ // Scaling filter is not explicitly set here, because it is done inside copyLayerInfo
+ // after checking the necessity based on the src/dest rect size and the transformation.
if (copyLayerInto(&layer, &skiaSrcRect, &skiaDestRect, bitmap)) {
copyResult = CopyResult::Success;
}
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 7932dcb..ea06632 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -156,7 +156,7 @@
private long mNativeContext;
- Lnb(int id) {
+ private Lnb(int id) {
mId = id;
}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index bcbc12b..08a33f1 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -43,7 +43,11 @@
import android.media.tv.tuner.frontend.FrontendStatus.FrontendStatusType;
import android.media.tv.tuner.frontend.OnTuneEventListener;
import android.media.tv.tuner.frontend.ScanCallback;
+import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerLnbRequest;
+import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
@@ -67,6 +71,7 @@
private static final String TAG = "MediaTvTuner";
private static final boolean DEBUG = false;
+ private static final int MSG_RESOURCE_LOST = 1;
private static final int MSG_ON_FILTER_EVENT = 2;
private static final int MSG_ON_FILTER_STATUS = 3;
private static final int MSG_ON_LNB_EVENT = 4;
@@ -93,6 +98,8 @@
}
private final Context mContext;
+ private final TunerResourceManager mTunerResourceManager;
+ private final int mClientId;
private List<Integer> mFrontendIds;
private Frontend mFrontend;
@@ -102,6 +109,7 @@
private List<Integer> mLnbIds;
private Lnb mLnb;
+ private Integer mLnbId;
@Nullable
private OnTuneEventListener mOnTuneEventListener;
@Nullable
@@ -115,6 +123,15 @@
@Nullable
private Executor mOnResourceLostListenerExecutor;
+
+ private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
+ new TunerResourceManager.ResourcesReclaimListener() {
+ @Override
+ public void onReclaimResources() {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_RESOURCE_LOST));
+ }
+ };
+
/**
* Constructs a Tuner instance.
*
@@ -127,6 +144,14 @@
@TvInputService.PriorityHintUseCaseType int useCase) {
nativeSetup();
mContext = context;
+ mTunerResourceManager = (TunerResourceManager)
+ context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
+
+ int[] clientId = new int[1];
+ ResourceClientProfile profile = new ResourceClientProfile(tvInputSessionId, useCase);
+ mTunerResourceManager.registerClientProfile(
+ profile, new HandlerExecutor(mHandler), mResourceListener, clientId);
+ mClientId = clientId[0];
}
/**
@@ -226,6 +251,7 @@
private native List<Integer> nativeGetLnbIds();
private native Lnb nativeOpenLnbById(int id);
+ private native Lnb nativeOpenLnbByName(String name);
private native Descrambler nativeOpenDescrambler();
@@ -275,6 +301,14 @@
}
break;
}
+ case MSG_RESOURCE_LOST: {
+ if (mOnResourceLostListener != null
+ && mOnResourceLostListenerExecutor != null) {
+ mOnResourceLostListenerExecutor.execute(
+ () -> mOnResourceLostListener.onResourceLost(Tuner.this));
+ }
+ break;
+ }
default:
// fall through
}
@@ -698,7 +732,10 @@
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(cb, "LnbCallback must not be null");
TunerUtils.checkTunerPermission(mContext);
- return openLnbByName(null, executor, cb);
+ if (mLnbId == null && !requestLnb()) {
+ return null;
+ }
+ return nativeOpenLnbById(mLnbId);
}
/**
@@ -714,11 +751,21 @@
@Nullable
public Lnb openLnbByName(@NonNull String name, @CallbackExecutor @NonNull Executor executor,
@NonNull LnbCallback cb) {
+ Objects.requireNonNull(name, "LNB name must not be null");
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(cb, "LnbCallback must not be null");
TunerUtils.checkTunerPermission(mContext);
- // TODO: use resource manager to get LNB ID.
- return new Lnb(0);
+ return nativeOpenLnbByName(name);
+ }
+
+ private boolean requestLnb() {
+ int[] lnbId = new int[1];
+ TunerLnbRequest request = new TunerLnbRequest(mClientId);
+ boolean granted = mTunerResourceManager.requestLnb(request, lnbId);
+ if (granted) {
+ mLnbId = lnbId[0];
+ }
+ return granted;
}
/**
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index dbd9db4..37a016e 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -69,7 +69,7 @@
*/
public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL;
- long mNativeContext;
+ private long mNativeContext;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index c1c6c62..d06356c 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -30,7 +30,7 @@
*/
@SystemApi
public class DvrRecorder implements AutoCloseable {
- long mNativeContext;
+ private long mNativeContext;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index 7b29494..8a29442 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
@@ -33,7 +34,7 @@
* @hide
*/
@SystemApi
-public class AlpFilterConfiguration extends FilterConfiguration {
+public final class AlpFilterConfiguration extends FilterConfiguration {
/**
* IPv4 packet type.
*/
@@ -123,9 +124,10 @@
/**
* Builder for {@link AlpFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private int mPacketType;
private int mLengthType;
+ private Settings mSettings;
private Builder() {
}
@@ -150,16 +152,20 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link AlpFilterConfiguration} object.
*/
@NonNull
public AlpFilterConfiguration build() {
return new AlpFilterConfiguration(mSettings, mPacketType, mLengthType);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 52bdb59..4777fe8 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -225,6 +225,7 @@
mCallback = cb;
mExecutor = executor;
}
+
/** @hide */
public FilterCallback getCallback() {
return mCallback;
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
index a8c9356..dd7e5fc 100644
--- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -16,7 +16,6 @@
package android.media.tv.tuner.filter;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -48,26 +47,4 @@
public Settings getSettings() {
return mSettings;
}
-
- /**
- * Builder for {@link FilterConfiguration}.
- *
- * @param <T> The subclass to be built.
- */
- public abstract static class Builder<T extends Builder<T>> {
- /* package */ Settings mSettings;
-
- /* package */ Builder() {
- }
-
- /**
- * Sets filter settings.
- */
- @NonNull
- public T setSettings(@Nullable Settings settings) {
- mSettings = settings;
- return self();
- }
- /* package */ abstract T self();
- }
}
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index a8dbfa5..04f3410 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -17,6 +17,7 @@
package android.media.tv.tuner.filter;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.Size;
import android.annotation.SystemApi;
@@ -29,7 +30,7 @@
* @hide
*/
@SystemApi
-public class IpFilterConfiguration extends FilterConfiguration {
+public final class IpFilterConfiguration extends FilterConfiguration {
private final byte[] mSrcIpAddress;
private final byte[] mDstIpAddress;
private final int mSrcPort;
@@ -104,12 +105,13 @@
/**
* Builder for {@link IpFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private byte[] mSrcIpAddress;
private byte[] mDstIpAddress;
private int mSrcPort;
private int mDstPort;
private boolean mPassthrough;
+ private Settings mSettings;
private Builder() {
}
@@ -156,6 +158,15 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link IpFilterConfiguration} object.
*/
@NonNull
@@ -169,10 +180,5 @@
return new IpFilterConfiguration(
mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, mPassthrough);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
index 0601829..c0453b4 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
@@ -17,6 +17,7 @@
package android.media.tv.tuner.filter;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
@@ -28,7 +29,7 @@
* @hide
*/
@SystemApi
-public class MmtpFilterConfiguration extends FilterConfiguration {
+public final class MmtpFilterConfiguration extends FilterConfiguration {
private final int mMmtpPid;
private MmtpFilterConfiguration(Settings settings, int mmtpPid) {
@@ -65,8 +66,9 @@
/**
* Builder for {@link IpFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private int mMmtpPid;
+ private Settings mSettings;
private Builder() {
}
@@ -81,16 +83,20 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link IpFilterConfiguration} object.
*/
@NonNull
public MmtpFilterConfiguration build() {
return new MmtpFilterConfiguration(mSettings, mMmtpPid);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
index ac4fc83..c5191bf 100644
--- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -17,6 +17,7 @@
package android.media.tv.tuner.filter;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
@@ -28,7 +29,7 @@
* @hide
*/
@SystemApi
-public class TlvFilterConfiguration extends FilterConfiguration {
+public final class TlvFilterConfiguration extends FilterConfiguration {
/**
* IPv4 packet type.
*/
@@ -108,10 +109,11 @@
/**
* Builder for {@link TlvFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private int mPacketType;
private boolean mIsCompressedIpPacket;
private boolean mPassthrough;
+ private Settings mSettings;
private Builder() {
}
@@ -144,6 +146,15 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link TlvFilterConfiguration} object.
*/
@NonNull
@@ -151,10 +162,5 @@
return new TlvFilterConfiguration(
mSettings, mPacketType, mIsCompressedIpPacket, mPassthrough);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
index 6a8b6da..a7140eb 100644
--- a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
@@ -17,6 +17,7 @@
package android.media.tv.tuner.filter;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
@@ -28,7 +29,7 @@
* @hide
*/
@SystemApi
-public class TsFilterConfiguration extends FilterConfiguration {
+public final class TsFilterConfiguration extends FilterConfiguration {
private final int mTpid;
private TsFilterConfiguration(Settings settings, int tpid) {
@@ -63,8 +64,9 @@
/**
* Builder for {@link TsFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private int mTpid;
+ private Settings mSettings;
private Builder() {
}
@@ -81,16 +83,20 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link TsFilterConfiguration} object.
*/
@NonNull
public TsFilterConfiguration build() {
return new TsFilterConfiguration(mSettings, mTpid);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index e99fd36f..1510b2d 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -125,9 +125,9 @@
/** @hide */
@IntDef(flag = true,
prefix = "CONSTELLATION_",
- value = {CONSTELLATION_UNDEFINED, CONSTELLATION_AUTO, CONSTELLATION_CONSTELLATION_QPSK,
- CONSTELLATION_CONSTELLATION_16QAM, CONSTELLATION_CONSTELLATION_64QAM,
- CONSTELLATION_CONSTELLATION_256QAM})
+ value = {CONSTELLATION_UNDEFINED, CONSTELLATION_AUTO, CONSTELLATION_QPSK,
+ CONSTELLATION_16QAM, CONSTELLATION_64QAM,
+ CONSTELLATION_256QAM})
@Retention(RetentionPolicy.SOURCE)
public @interface Constellation {}
@@ -142,22 +142,22 @@
/**
* QPSK Constellation.
*/
- public static final int CONSTELLATION_CONSTELLATION_QPSK =
+ public static final int CONSTELLATION_QPSK =
Constants.FrontendDvbtConstellation.CONSTELLATION_QPSK;
/**
* 16QAM Constellation.
*/
- public static final int CONSTELLATION_CONSTELLATION_16QAM =
+ public static final int CONSTELLATION_16QAM =
Constants.FrontendDvbtConstellation.CONSTELLATION_16QAM;
/**
* 64QAM Constellation.
*/
- public static final int CONSTELLATION_CONSTELLATION_64QAM =
+ public static final int CONSTELLATION_64QAM =
Constants.FrontendDvbtConstellation.CONSTELLATION_64QAM;
/**
* 256QAM Constellation.
*/
- public static final int CONSTELLATION_CONSTELLATION_256QAM =
+ public static final int CONSTELLATION_256QAM =
Constants.FrontendDvbtConstellation.CONSTELLATION_256QAM;
@@ -275,11 +275,11 @@
@IntDef(flag = true,
prefix = "GUARD_INTERVAL_",
value = {GUARD_INTERVAL_UNDEFINED, GUARD_INTERVAL_AUTO,
- GUARD_INTERVAL_INTERVAL_1_32, GUARD_INTERVAL_INTERVAL_1_16,
- GUARD_INTERVAL_INTERVAL_1_8, GUARD_INTERVAL_INTERVAL_1_4,
- GUARD_INTERVAL_INTERVAL_1_128,
- GUARD_INTERVAL_INTERVAL_19_128,
- GUARD_INTERVAL_INTERVAL_19_256})
+ GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_16,
+ GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_4,
+ GUARD_INTERVAL_1_128,
+ GUARD_INTERVAL_19_128,
+ GUARD_INTERVAL_19_256})
@Retention(RetentionPolicy.SOURCE)
public @interface GuardInterval {}
@@ -295,37 +295,37 @@
/**
* 1/32 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_32 =
+ public static final int GUARD_INTERVAL_1_32 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_32;
/**
* 1/16 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_16 =
+ public static final int GUARD_INTERVAL_1_16 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_16;
/**
* 1/8 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_8 =
+ public static final int GUARD_INTERVAL_1_8 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_8;
/**
* 1/4 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_4 =
+ public static final int GUARD_INTERVAL_1_4 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_4;
/**
* 1/128 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_128 =
+ public static final int GUARD_INTERVAL_1_128 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_128;
/**
* 19/128 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_19_128 =
+ public static final int GUARD_INTERVAL_19_128 =
Constants.FrontendDvbtGuardInterval.INTERVAL_19_128;
/**
* 19/256 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_19_256 =
+ public static final int GUARD_INTERVAL_19_256 =
Constants.FrontendDvbtGuardInterval.INTERVAL_19_256;
/** @hide */
@@ -435,14 +435,14 @@
* Gets Code Rate for High Priority level.
*/
@CodeRate
- public int getHpCodeRate() {
+ public int getHighPriorityCodeRate() {
return mHpCodeRate;
}
/**
* Gets Code Rate for Low Priority level.
*/
@CodeRate
- public int getLpCodeRate() {
+ public int getLowPriorityCodeRate() {
return mLpCodeRate;
}
/**
@@ -560,7 +560,7 @@
* Sets Code Rate for High Priority level.
*/
@NonNull
- public Builder setHpCodeRate(@CodeRate int hpCodeRate) {
+ public Builder setHighPriorityCodeRate(@CodeRate int hpCodeRate) {
mHpCodeRate = hpCodeRate;
return this;
}
@@ -568,7 +568,7 @@
* Sets Code Rate for Low Priority level.
*/
@NonNull
- public Builder setLpCodeRate(@CodeRate int lpCodeRate) {
+ public Builder setLowPriorityCodeRate(@CodeRate int lpCodeRate) {
mLpCodeRate = lpCodeRate;
return this;
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 737c95d..893e516 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -242,13 +242,6 @@
});
}
-void JMediaCodec::releaseAsync() {
- if (mCodec != NULL) {
- mCodec->releaseAsync();
- }
- mInitStatus = NO_INIT;
-}
-
JMediaCodec::~JMediaCodec() {
if (mLooper != NULL) {
/* MediaCodec and looper should have been released explicitly already
@@ -1131,10 +1124,7 @@
}
static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
- sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec != NULL) {
- codec->releaseAsync();
- }
+ setMediaCodec(env, thiz, NULL);
}
static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
@@ -2807,7 +2797,7 @@
static void android_media_MediaCodec_native_finalize(
JNIEnv *env, jobject thiz) {
- setMediaCodec(env, thiz, NULL);
+ android_media_MediaCodec_release(env, thiz);
}
// MediaCodec.LinearBlock
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 400ce1b..8899fee 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -61,7 +61,6 @@
void registerSelf();
void release();
- void releaseAsync();
status_t enableOnFrameRenderedListener(jboolean enable);
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 273c776..a37c9e5 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -34,19 +34,28 @@
using ::android::hardware::Void;
using ::android::hardware::hidl_bitfield;
using ::android::hardware::hidl_vec;
+using ::android::hardware::tv::tuner::V1_0::AudioExtraMetaData;
+using ::android::hardware::tv::tuner::V1_0::Constant;
using ::android::hardware::tv::tuner::V1_0::DataFormat;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterIpPayloadEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterMmtpRecordEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionBits;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterTemiEvent;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterTsRecordEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxIpAddress;
using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
@@ -129,13 +138,16 @@
jfieldID filterContext;
jfieldID timeFilterContext;
jfieldID descramblerContext;
- jfieldID dvrContext;
+ jfieldID dvrRecorderContext;
+ jfieldID dvrPlaybackContext;
jmethodID frontendInitID;
jmethodID filterInitID;
jmethodID timeFilterInitID;
- jmethodID dvrInitID;
+ jmethodID dvrRecorderInitID;
+ jmethodID dvrPlaybackInitID;
jmethodID onFrontendEventID;
jmethodID onFilterStatusID;
+ jmethodID onFilterEventID;
jmethodID lnbInitID;
jmethodID onLnbEventID;
jmethodID descramblerInitID;
@@ -248,48 +260,287 @@
return linearBlock;
}
-jobject FilterCallback::getMediaEvent(const DemuxFilterEvent::Event& event) {
+jobjectArray FilterCallback::getSectionEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jclass clazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
- jmethodID eventInit = env->GetMethodID(clazz,
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/SectionEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIII)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterSectionEvent sectionEvent = event.section();
+
+ jint tableId = static_cast<jint>(sectionEvent.tableId);
+ jint version = static_cast<jint>(sectionEvent.version);
+ jint sectionNum = static_cast<jint>(sectionEvent.sectionNum);
+ jint dataLength = static_cast<jint>(sectionEvent.dataLength);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, tableId, version, sectionNum, dataLength);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getMediaEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz,
"<init>",
"(IZJJJLandroid/media/MediaCodec$LinearBlock;"
"ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V");
- DemuxFilterMediaEvent mediaEvent = event.media();
- uint32_t dataLength = mediaEvent.dataLength;
- const native_handle_t* h = mediaEvent.avMemory.getNativeHandle();
- jobject block = handleToLinearBlock(h, dataLength);
- // TODO: handle other fields
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterMediaEvent mediaEvent = event.media();
- return env->NewObject(clazz, eventInit, (jint) 0, (jboolean) 0, (jlong) 0, (jlong) 0, (jlong) 0,
- block, (jboolean) 0, (jlong) 0, (jint) 0, (jboolean) 0, NULL);
+ jobject audioDescriptor = NULL;
+ if (mediaEvent.extraMetaData.getDiscriminator()
+ == DemuxFilterMediaEvent::ExtraMetaData::hidl_discriminator::audio) {
+ jclass adClazz = env->FindClass("android/media/tv/tuner/filter/AudioDescriptor");
+ jmethodID adInit = env->GetMethodID(adClazz, "<init>", "(BBCBBB)V");
+
+ AudioExtraMetaData ad = mediaEvent.extraMetaData.audio();
+ jbyte adFade = static_cast<jbyte>(ad.adFade);
+ jbyte adPan = static_cast<jbyte>(ad.adPan);
+ jchar versionTextTag = static_cast<jchar>(ad.versionTextTag);
+ jbyte adGainCenter = static_cast<jbyte>(ad.adGainCenter);
+ jbyte adGainFront = static_cast<jbyte>(ad.adGainFront);
+ jbyte adGainSurround = static_cast<jbyte>(ad.adGainSurround);
+
+ audioDescriptor =
+ env->NewObject(adClazz, adInit, adFade, adPan, versionTextTag, adGainCenter,
+ adGainFront, adGainSurround);
+ }
+
+ jlong dataLength = static_cast<jlong>(mediaEvent.dataLength);
+ const native_handle_t* h = NULL;
+ jobject block = NULL;
+ if (mediaEvent.avMemory != NULL) {
+ h = mediaEvent.avMemory.getNativeHandle();
+ block = handleToLinearBlock(h, dataLength);
+ }
+
+ jint streamId = static_cast<jint>(mediaEvent.streamId);
+ jboolean isPtsPresent = static_cast<jboolean>(mediaEvent.isPtsPresent);
+ jlong pts = static_cast<jlong>(mediaEvent.pts);
+ jlong offset = static_cast<jlong>(mediaEvent.offset);
+ jboolean isSecureMemory = static_cast<jboolean>(mediaEvent.isSecureMemory);
+ jlong avDataId = static_cast<jlong>(mediaEvent.avDataId);
+ jint mpuSequenceNumber = static_cast<jint>(mediaEvent.mpuSequenceNumber);
+ jboolean isPesPrivateData = static_cast<jboolean>(mediaEvent.isPesPrivateData);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, dataLength,
+ offset, block, isSecureMemory, avDataId, mpuSequenceNumber, isPesPrivateData,
+ audioDescriptor);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getPesEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/PesEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(III)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterPesEvent pesEvent = event.pes();
+
+ jint streamId = static_cast<jint>(pesEvent.streamId);
+ jint dataLength = static_cast<jint>(pesEvent.dataLength);
+ jint mpuSequenceNumber = static_cast<jint>(pesEvent.mpuSequenceNumber);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, streamId, dataLength, mpuSequenceNumber);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getTsRecordEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TsRecordEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJ)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterTsRecordEvent tsRecordEvent = event.tsRecord();
+ DemuxPid pid = tsRecordEvent.pid;
+
+ jint jpid = static_cast<jint>(Constant::INVALID_TS_PID);
+
+ if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::tPid) {
+ jpid = static_cast<jint>(pid.tPid());
+ } else if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::mmtpPid) {
+ jpid = static_cast<jint>(pid.mmtpPid());
+ }
+
+ jint sc = 0;
+
+ if (tsRecordEvent.scIndexMask.getDiscriminator()
+ == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::sc) {
+ sc = static_cast<jint>(tsRecordEvent.scIndexMask.sc());
+ } else if (tsRecordEvent.scIndexMask.getDiscriminator()
+ == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::scHevc) {
+ sc = static_cast<jint>(tsRecordEvent.scIndexMask.scHevc());
+ }
+
+ jint ts = static_cast<jint>(tsRecordEvent.tsIndexMask);
+
+ jlong byteNumber = static_cast<jlong>(tsRecordEvent.byteNumber);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getMmtpRecordEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MmtpRecordEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJ)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterMmtpRecordEvent mmtpRecordEvent = event.mmtpRecord();
+
+ jint scHevcIndexMask = static_cast<jint>(mmtpRecordEvent.scHevcIndexMask);
+ jlong byteNumber = static_cast<jlong>(mmtpRecordEvent.byteNumber);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getDownloadEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/DownloadEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIII)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterDownloadEvent downloadEvent = event.download();
+
+ jint itemId = static_cast<jint>(downloadEvent.itemId);
+ jint mpuSequenceNumber = static_cast<jint>(downloadEvent.mpuSequenceNumber);
+ jint itemFragmentIndex = static_cast<jint>(downloadEvent.itemFragmentIndex);
+ jint lastItemFragmentIndex = static_cast<jint>(downloadEvent.lastItemFragmentIndex);
+ jint dataLength = static_cast<jint>(downloadEvent.dataLength);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, itemId, mpuSequenceNumber, itemFragmentIndex,
+ lastItemFragmentIndex, dataLength);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getIpPayloadEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpPayloadEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(I)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterIpPayloadEvent ipPayloadEvent = event.ipPayload();
+ jint dataLength = static_cast<jint>(ipPayloadEvent.dataLength);
+ jobject obj = env->NewObject(eventClazz, eventInit, dataLength);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getTemiEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TemiEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(JB[B)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterTemiEvent temiEvent = event.temi();
+ jlong pts = static_cast<jlong>(temiEvent.pts);
+ jbyte descrTag = static_cast<jbyte>(temiEvent.descrTag);
+ std::vector<uint8_t> descrData = temiEvent.descrData;
+
+ jbyteArray array = env->NewByteArray(descrData.size());
+ env->SetByteArrayRegion(
+ array, 0, descrData.size(), reinterpret_cast<jbyte*>(&descrData[0]));
+
+ jobject obj = env->NewObject(eventClazz, eventInit, pts, descrTag, array);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
}
Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) {
ALOGD("FilterCallback::onFilterEvent");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jclass clazz = env->FindClass("android/media/tv/tuner/filter/Filter");
std::vector<DemuxFilterEvent::Event> events = filterEvent.events;
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/FilterEvent");
jobjectArray array = env->NewObjectArray(events.size(), eventClazz, NULL);
- for (int i = 0; i < events.size(); i++) {
- auto event = events[i];
- if (event.getDiscriminator() == DemuxFilterEvent::Event::hidl_discriminator::media) {
- env->SetObjectArrayElement(array, i, getMediaEvent(event));
+ if (!events.empty()) {
+ auto event = events[0];
+ switch (event.getDiscriminator()) {
+ case DemuxFilterEvent::Event::hidl_discriminator::media: {
+ array = getMediaEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::section: {
+ array = getSectionEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::pes: {
+ array = getPesEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::tsRecord: {
+ array = getTsRecordEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::mmtpRecord: {
+ array = getMmtpRecordEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::download: {
+ array = getDownloadEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::ipPayload: {
+ array = getIpPayloadEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::temi: {
+ array = getTemiEvent(array, events);
+ break;
+ }
+ default: {
+ break;
+ }
}
}
env->CallVoidMethod(
mFilter,
- env->GetMethodID(clazz, "onFilterEvent",
- "([Landroid/media/tv/tuner/filter/FilterEvent;)V"),
+ gFields.onFilterEventID,
array);
return Void();
}
+
Return<void> FilterCallback::onFilterStatus(const DemuxFilterStatus status) {
ALOGD("FilterCallback::onFilterStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -308,9 +559,16 @@
/////////////// Filter ///////////////////////
-Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {}
+Filter::Filter(sp<IFilter> sp, jobject obj) : mFilterSp(sp) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ mFilterObj = env->NewWeakGlobalRef(obj);
+}
Filter::~Filter() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ env->DeleteWeakGlobalRef(mFilterObj);
+ mFilterObj = NULL;
EventFlag::deleteEventFlag(&mFilterMQEventFlag);
}
@@ -816,6 +1074,37 @@
return lnbObj;
}
+jobject JTuner::openLnbByName(jstring name) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ std::string lnbName(env->GetStringUTFChars(name, nullptr));
+ sp<ILnb> iLnbSp;
+ Result res;
+ LnbId id;
+ mTuner->openLnbByName(lnbName, [&](Result r, LnbId lnbId, const sp<ILnb>& lnb) {
+ res = r;
+ iLnbSp = lnb;
+ id = lnbId;
+ });
+ if (res != Result::SUCCESS || iLnbSp == nullptr) {
+ ALOGE("Failed to open lnb");
+ return NULL;
+ }
+ mLnb = iLnbSp;
+ sp<LnbCallback> lnbCb = new LnbCallback(mObject, id);
+ mLnb->setCallback(lnbCb);
+
+ jobject lnbObj = env->NewObject(
+ env->FindClass("android/media/tv/tuner/Lnb"),
+ gFields.lnbInitID,
+ id);
+
+ sp<Lnb> lnbSp = new Lnb(iLnbSp, lnbObj);
+ lnbSp->incStrong(lnbObj);
+ env->SetLongField(lnbObj, gFields.lnbContext, (jlong) lnbSp.get());
+
+ return lnbObj;
+}
+
int JTuner::tune(const FrontendSettings& settings) {
if (mFe == NULL) {
ALOGE("frontend is not initialized");
@@ -1046,7 +1335,7 @@
return timeFilterObj;
}
-jobject JTuner::openDvr(DvrType type, int bufferSize) {
+jobject JTuner::openDvr(DvrType type, jlong bufferSize) {
ALOGD("JTuner::openDvr");
if (mDemux == NULL) {
if (openDemux() != Result::SUCCESS) {
@@ -1055,24 +1344,38 @@
}
sp<IDvr> iDvrSp;
sp<DvrCallback> callback = new DvrCallback();
- mDemux->openDvr(type, bufferSize, callback,
- [&](Result, const sp<IDvr>& dvr) {
+ Result res;
+ mDemux->openDvr(type, (uint32_t) bufferSize, callback,
+ [&](Result r, const sp<IDvr>& dvr) {
+ res = r;
iDvrSp = dvr;
});
- if (iDvrSp == NULL) {
+ if (res != Result::SUCCESS || iDvrSp == NULL) {
return NULL;
}
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jobject dvrObj =
- env->NewObject(
- env->FindClass("android/media/tv/tuner/dvr/Dvr"),
- gFields.dvrInitID,
- mObject);
- sp<Dvr> dvrSp = new Dvr(iDvrSp, dvrObj);
- dvrSp->incStrong(dvrObj);
- env->SetLongField(dvrObj, gFields.dvrContext, (jlong)dvrSp.get());
+ jobject dvrObj;
+ if (type == DvrType::RECORD) {
+ dvrObj =
+ env->NewObject(
+ env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"),
+ gFields.dvrRecorderInitID,
+ mObject);
+ sp<Dvr> dvrSp = new Dvr(iDvrSp, dvrObj);
+ dvrSp->incStrong(dvrObj);
+ env->SetLongField(dvrObj, gFields.dvrRecorderContext, (jlong)dvrSp.get());
+ } else {
+ dvrObj =
+ env->NewObject(
+ env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"),
+ gFields.dvrPlaybackInitID,
+ mObject);
+ sp<Dvr> dvrSp = new Dvr(iDvrSp, dvrObj);
+ dvrSp->incStrong(dvrObj);
+ env->SetLongField(dvrObj, gFields.dvrPlaybackContext, (jlong)dvrSp.get());
+ }
callback->setDvr(dvrObj);
@@ -1596,7 +1899,11 @@
}
static sp<Dvr> getDvr(JNIEnv *env, jobject dvr) {
- return (Dvr *)env->GetLongField(dvr, gFields.dvrContext);
+ bool isRecorder =
+ env->IsInstanceOf(dvr, env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"));
+ jfieldID fieldId =
+ isRecorder ? gFields.dvrRecorderContext : gFields.dvrPlaybackContext;
+ return (Dvr *)env->GetLongField(dvr, fieldId);
}
static void android_media_tv_Tuner_native_init(JNIEnv *env) {
@@ -1616,8 +1923,7 @@
jclass lnbClazz = env->FindClass("android/media/tv/tuner/Lnb");
gFields.lnbContext = env->GetFieldID(lnbClazz, "mNativeContext", "J");
- gFields.lnbInitID =
- env->GetMethodID(lnbClazz, "<init>", "(I)V");
+ gFields.lnbInitID = env->GetMethodID(lnbClazz, "<init>", "(I)V");
jclass filterClazz = env->FindClass("android/media/tv/tuner/filter/Filter");
gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J");
@@ -1625,6 +1931,9 @@
env->GetMethodID(filterClazz, "<init>", "(I)V");
gFields.onFilterStatusID =
env->GetMethodID(filterClazz, "onFilterStatus", "(I)V");
+ gFields.onFilterEventID =
+ env->GetMethodID(filterClazz, "onFilterEvent",
+ "([Landroid/media/tv/tuner/filter/FilterEvent;)V");
jclass timeFilterClazz = env->FindClass("android/media/tv/tuner/filter/TimeFilter");
gFields.timeFilterContext = env->GetFieldID(timeFilterClazz, "mNativeContext", "J");
@@ -1635,9 +1944,13 @@
gFields.descramblerInitID =
env->GetMethodID(descramblerClazz, "<init>", "()V");
- jclass dvrClazz = env->FindClass("android/media/tv/tuner/dvr/Dvr");
- gFields.dvrContext = env->GetFieldID(dvrClazz, "mNativeContext", "J");
- gFields.dvrInitID = env->GetMethodID(dvrClazz, "<init>", "()V");
+ jclass dvrRecorderClazz = env->FindClass("android/media/tv/tuner/dvr/DvrRecorder");
+ gFields.dvrRecorderContext = env->GetFieldID(dvrRecorderClazz, "mNativeContext", "J");
+ gFields.dvrRecorderInitID = env->GetMethodID(dvrRecorderClazz, "<init>", "()V");
+
+ jclass dvrPlaybackClazz = env->FindClass("android/media/tv/tuner/dvr/DvrPlayback");
+ gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J");
+ gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "<init>", "()V");
jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock");
gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V");
@@ -1737,6 +2050,12 @@
return tuner->openLnbById(id);
}
+static jobject android_media_tv_Tuner_open_lnb_by_name(JNIEnv *env, jobject thiz, jstring name) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openLnbByName(name);
+}
+
+
static jobject android_media_tv_Tuner_open_filter(
JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) {
sp<JTuner> tuner = getTuner(env, thiz);
@@ -2359,13 +2678,15 @@
}
static jobject android_media_tv_Tuner_open_dvr_recorder(
- JNIEnv* /* env */, jobject /* thiz */, jlong /* bufferSize */) {
- return NULL;
+ JNIEnv* env, jobject thiz, jlong bufferSize) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openDvr(DvrType::RECORD, bufferSize);
}
static jobject android_media_tv_Tuner_open_dvr_playback(
- JNIEnv* /* env */, jobject /* thiz */, jlong /* bufferSize */) {
- return NULL;
+ JNIEnv* env, jobject thiz, jlong bufferSize) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openDvr(DvrType::PLAYBACK, bufferSize);
}
static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv*, jobject) {
@@ -2419,11 +2740,13 @@
}
static int android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
+
sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
if (dvrSp == NULL) {
ALOGD("Failed to start dvr: dvr not found");
return false;
}
+
Result result = dvrSp->start();
return (int) result;
}
@@ -2629,6 +2952,8 @@
(void *)android_media_tv_Tuner_get_lnb_ids },
{ "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Lnb;",
(void *)android_media_tv_Tuner_open_lnb_by_id },
+ { "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;",
+ (void *)android_media_tv_Tuner_open_lnb_by_name },
{ "nativeOpenDescrambler", "()Landroid/media/tv/tuner/Descrambler;",
(void *)android_media_tv_Tuner_open_descrambler },
{ "nativeOpenDvrRecorder", "(J)Landroid/media/tv/tuner/dvr/DvrRecorder;",
@@ -2671,7 +2996,7 @@
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_descrambler },
};
-static const JNINativeMethod gDvrMethods[] = {
+static const JNINativeMethod gDvrRecorderMethods[] = {
{ "nativeAttachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I",
(void *)android_media_tv_Tuner_attach_filter },
{ "nativeDetachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I",
@@ -2683,14 +3008,22 @@
{ "nativeFlushDvr", "()I", (void *)android_media_tv_Tuner_flush_dvr },
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_dvr },
{ "nativeSetFileDescriptor", "(I)V", (void *)android_media_tv_Tuner_dvr_set_fd },
-};
-
-static const JNINativeMethod gDvrRecorderMethods[] = {
{ "nativeWrite", "(J)J", (void *)android_media_tv_Tuner_write_dvr },
{ "nativeWrite", "([BJJ)J", (void *)android_media_tv_Tuner_write_dvr_to_array },
};
static const JNINativeMethod gDvrPlaybackMethods[] = {
+ { "nativeAttachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I",
+ (void *)android_media_tv_Tuner_attach_filter },
+ { "nativeDetachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I",
+ (void *)android_media_tv_Tuner_detach_filter },
+ { "nativeConfigureDvr", "(Landroid/media/tv/tuner/dvr/DvrSettings;)I",
+ (void *)android_media_tv_Tuner_configure_dvr },
+ { "nativeStartDvr", "()I", (void *)android_media_tv_Tuner_start_dvr },
+ { "nativeStopDvr", "()I", (void *)android_media_tv_Tuner_stop_dvr },
+ { "nativeFlushDvr", "()I", (void *)android_media_tv_Tuner_flush_dvr },
+ { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_dvr },
+ { "nativeSetFileDescriptor", "(I)V", (void *)android_media_tv_Tuner_dvr_set_fd },
{ "nativeRead", "(J)J", (void *)android_media_tv_Tuner_read_dvr },
{ "nativeRead", "([BJJ)J", (void *)android_media_tv_Tuner_read_dvr_from_array },
};
@@ -2731,13 +3064,6 @@
return false;
}
if (AndroidRuntime::registerNativeMethods(
- env, "android/media/tv/tuner/dvr/Dvr",
- gDvrMethods,
- NELEM(gDvrMethods)) != JNI_OK) {
- ALOGE("Failed to register dvr native methods");
- return false;
- }
- if (AndroidRuntime::registerNativeMethods(
env, "android/media/tv/tuner/dvr/DvrRecorder",
gDvrRecorderMethods,
NELEM(gDvrRecorderMethods)) != JNI_OK) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index fec4cd8..5d2bba6 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -114,7 +114,22 @@
jobject handleToLinearBlock(const native_handle_t* handle, uint32_t size);
private:
jweak mFilter;
- jobject getMediaEvent(const DemuxFilterEvent::Event& event);
+ jobjectArray getSectionEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getMediaEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getPesEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getTsRecordEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getMmtpRecordEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getDownloadEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getIpPayloadEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getTemiEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
};
struct FrontendCallback : public IFrontendCallback {
@@ -129,7 +144,7 @@
};
struct Filter : public RefBase {
- Filter(sp<IFilter> sp, jweak obj);
+ Filter(sp<IFilter> sp, jobject obj);
~Filter();
int close();
sp<IFilter> getIFilter();
@@ -165,10 +180,11 @@
int setLna(bool enable);
jobject getLnbIds();
jobject openLnbById(int id);
+ jobject openLnbByName(jstring name);
jobject openFilter(DemuxFilterType type, int bufferSize);
jobject openTimeFilter();
jobject openDescrambler();
- jobject openDvr(DvrType type, int bufferSize);
+ jobject openDvr(DvrType type, jlong bufferSize);
protected:
Result openDemux();
diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h
index 15b39f2..30ad220 100644
--- a/media/jni/soundpool/StreamManager.h
+++ b/media/jni/soundpool/StreamManager.h
@@ -70,9 +70,10 @@
static int staticFunction(void *data) {
JavaThread *jt = static_cast<JavaThread *>(data);
jt->mF();
+ jt->mIsClosed = true; // set the flag that we are closed
+ // now before we allow the destructor to execute;
+ // otherwise there may be a use after free.
jt->mPromise.set_value();
- jt->mIsClosed = true; // publicly inform that we are closed
- // after we have accessed all variables.
return 0;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index c529952..6354ccd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -320,6 +320,15 @@
public void onCameraAccessPrioritiesChanged() {
Log.v(TAG, "Camera access permission change");
}
+ @Override
+ public void onCameraOpened(String cameraId, String clientPackageName) {
+ Log.v(TAG, String.format("Camera %s is opened by client package %s",
+ cameraId, clientPackageName));
+ }
+ @Override
+ public void onCameraClosed(String cameraId) {
+ Log.v(TAG, String.format("Camera %s is closed", cameraId));
+ }
}
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 6f985a4..8292d30 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -24,7 +24,6 @@
import com.android.keyguard.KeyguardViewController;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
-import com.android.systemui.car.CarNotificationInterruptionStateProvider;
import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
@@ -41,7 +40,6 @@
import com.android.systemui.statusbar.car.CarStatusBar;
import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
@@ -49,6 +47,8 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -65,10 +65,6 @@
@Module(includes = {DividerModule.class})
abstract class CarSystemUIModule {
- @Binds
- abstract NotificationInterruptionStateProvider bindNotificationInterruptionStateProvider(
- CarNotificationInterruptionStateProvider notificationInterruptionStateProvider);
-
@Singleton
@Provides
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME)
@@ -106,6 +102,11 @@
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
@Binds
+ @Singleton
+ public abstract BatteryController provideBatteryController(
+ BatteryControllerImpl controllerImpl);
+
+ @Binds
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
deleted file mode 100644
index 447e579..0000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car;
-
-import android.content.Context;
-
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.policy.BatteryController;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/** Auto-specific implementation of {@link NotificationInterruptionStateProvider}. */
-@Singleton
-public class CarNotificationInterruptionStateProvider extends
- NotificationInterruptionStateProvider {
-
- @Inject
- public CarNotificationInterruptionStateProvider(Context context,
- NotificationFilter filter,
- StatusBarStateController stateController,
- BatteryController batteryController) {
- super(context, filter, stateController, batteryController);
- }
-
- @Override
- public boolean shouldHeadsUp(NotificationEntry entry) {
- // Because space is usually constrained in the auto use-case, there should not be a
- // pinned notification when the shade has been expanded. Ensure this by not pinning any
- // notification if the shade is already opened.
- if (!getPresenter().isPresenterFullyCollapsed()) {
- return false;
- }
-
- return super.shouldHeadsUp(entry);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index b2e2104..411f14d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -95,13 +95,15 @@
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -249,7 +251,7 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
NotificationAlertingManager notificationAlertingManager,
@@ -335,7 +337,7 @@
remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
- notificationInterruptionStateProvider,
+ notificationInterruptStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
notificationAlertingManager,
@@ -488,6 +490,22 @@
.isCurrentUserSetupInProgress();
}
});
+
+ mNotificationInterruptStateProvider.addSuppressor(new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return TAG;
+ }
+
+ @Override
+ public boolean suppressInterruptions(NotificationEntry entry) {
+ // Because space is usually constrained in the auto use-case, there should not be a
+ // pinned notification when the shade has been expanded.
+ // Ensure this by not allowing any interruptions (ie: pinning any notifications) if
+ // the shade is already opened.
+ return !getPresenter().isPresenterFullyCollapsed();
+ }
+ });
}
@Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 4754118..160268b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -62,13 +62,13 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.dagger.StatusBarDependenciesModule;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationRowModule;
@@ -146,7 +146,7 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
NotificationAlertingManager notificationAlertingManager,
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e8e1d0b..00f6bcb 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1039,7 +1039,7 @@
<!-- Title for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
<string name="accessibility_display_daltonizer_preference_title">Color correction</string>
<!-- Subtitle for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
- <string name="accessibility_display_daltonizer_preference_subtitle">Color correction helps people with colorblindness see more accurate colors</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle">Color correction helps the device display more accurate colors. Color correction may be helpful for people with colorblindness.</string>
<!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
<string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 1e888da..18d8f14 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -19,7 +19,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -121,8 +120,6 @@
verify(currentDevice).disconnect();
verify(device).connect();
- verify(mCallback).onSelectedDeviceStateChanged(any(),
- eq(LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED));
}
@Test
@@ -368,7 +365,8 @@
mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_2);
assertThat(mLocalMediaManager.getCurrentConnectedDevice()).isEqualTo(device2);
- verify(mCallback).onDeviceAttributesChanged();
+ verify(mCallback).onSelectedDeviceStateChanged(device2,
+ LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
}
@Test
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 8fa98c8..d350d9d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -141,6 +141,8 @@
Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL,
Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
Settings.Secure.UI_NIGHT_MODE,
+ Settings.Secure.DARK_THEME_CUSTOM_START_TIME,
+ Settings.Secure.DARK_THEME_CUSTOM_END_TIME,
Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST,
Settings.Secure.SKIP_DIRECTION,
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 75c5f95..4d33b62 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -28,6 +28,7 @@
import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.TILE_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
@@ -235,7 +236,9 @@
VALIDATORS.put(Secure.AWARE_TAP_PAUSE_TOUCH_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.ODI_CAPTIONS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DARK_MODE_DIALOG_SEEN, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.UI_NIGHT_MODE, new InclusiveIntegerRangeValidator(0, 2));
+ VALIDATORS.put(Secure.UI_NIGHT_MODE, NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(Secure.DARK_THEME_CUSTOM_START_TIME, NONE_NEGATIVE_LONG_VALIDATOR);
+ VALIDATORS.put(Secure.DARK_THEME_CUSTOM_END_TIME, NONE_NEGATIVE_LONG_VALIDATOR);
VALIDATORS.put(Secure.GLOBAL_ACTIONS_PANEL_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.AWARE_LOCK_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DISPLAY_DENSITY_FORCED, NON_NEGATIVE_INTEGER_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 71c7544..8d5c6e6 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -207,4 +207,15 @@
static final Validator ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR =
new AccessibilityShortcutTargetListValidator();
+
+ static final Validator NONE_NEGATIVE_LONG_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ return Long.parseLong(value) >= 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 36bb8ef..b6e31d2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -75,6 +75,9 @@
sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
sBroadcastOnRestore.add(Settings.Global.BLUETOOTH_ON);
+ sBroadcastOnRestore.add(Settings.Secure.UI_NIGHT_MODE);
+ sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_START_TIME);
+ sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME);
}
private interface SettingsLookup {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 2dc6f39..5a9d749 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2778,6 +2778,11 @@
public boolean insertSettingLocked(int type, int userId, String name, String value,
String tag, boolean makeDefault, boolean forceNonSystemPackage, String packageName,
boolean forceNotify, Set<String> criticalSettings, boolean overrideableByRestore) {
+ if (overrideableByRestore != Settings.DEFAULT_OVERRIDEABLE_BY_RESTORE) {
+ getContext().enforceCallingOrSelfPermission(
+ Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE,
+ "Caller is not allowed to modify settings overrideable by restore");
+ }
final int key = makeKey(type, userId);
boolean success = false;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index cd62420..2d351c7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -1259,7 +1259,8 @@
public boolean reset() {
// overrideableByRestore = true as resetting to default value isn't considered a
// modification.
- return update(this.defaultValue, false, packageName, null, true, true);
+ return update(this.defaultValue, false, packageName, null, true, true,
+ /* resetToDefault */ true);
}
public boolean isTransient() {
@@ -1272,6 +1273,13 @@
public boolean update(String value, boolean setDefault, String packageName, String tag,
boolean forceNonSystemPackage, boolean overrideableByRestore) {
+ return update(value, setDefault, packageName, tag, forceNonSystemPackage,
+ overrideableByRestore, /* resetToDefault */ false);
+ }
+
+ private boolean update(String value, boolean setDefault, String packageName, String tag,
+ boolean forceNonSystemPackage, boolean overrideableByRestore,
+ boolean resetToDefault) {
if (NULL_VALUE.equals(value)) {
value = null;
}
@@ -1305,7 +1313,7 @@
}
// isValuePreservedInRestore shouldn't change back to false if it has been set to true.
- boolean isPreserved = this.isValuePreservedInRestore || !overrideableByRestore;
+ boolean isPreserved = shouldPreserveSetting(overrideableByRestore, resetToDefault);
// Is something gonna change?
if (Objects.equals(value, this.value)
@@ -1329,6 +1337,17 @@
+ " packageName=" + packageName + " tag=" + tag
+ " defaultFromSystem=" + defaultFromSystem + "}";
}
+
+ private boolean shouldPreserveSetting(boolean overrideableByRestore,
+ boolean resetToDefault) {
+ if (resetToDefault) {
+ // By default settings are not marked as preserved.
+ return false;
+ }
+
+ // isValuePreservedInRestore shouldn't change back to false if it has been set to true.
+ return this.isValuePreservedInRestore || !overrideableByRestore;
+ }
}
/**
diff --git a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
index bb9e6f6..9134d87 100644
--- a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
@@ -277,6 +277,27 @@
}
@Test
+ public void testPositiveLongValidator_zero() {
+ assertTrue(SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR.validate("0"));
+ }
+
+ @Test
+ public void testPositiveLongValidator_negative() {
+ assertFalse(SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR.validate("-5"));
+ }
+
+
+ @Test
+ public void testPositiveLongValidator_positive() {
+ assertTrue(SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR.validate("5"));
+ }
+
+ @Test
+ public void testPositiveLongValidator_floatFormat() {
+ assertFalse(SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR.validate("4.4756"));
+ }
+
+ @Test
public void testTTSListValidator_withNullInput_returnsFalse() {
assertFalse(SettingsValidators.TTS_LIST_VALIDATOR.validate(null));
}
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index b855d87..6a3c661 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -241,6 +241,18 @@
assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
}
+ public void testResetSetting_preservedFlagIsReset() {
+ SettingsState settingsState = getSettingStateObject();
+ // Initialize the setting.
+ settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
+ // Update the setting so that preserved flag is set.
+ settingsState.insertSettingLocked(SETTING_NAME, "2", null, false, TEST_PACKAGE);
+
+ settingsState.resetSettingLocked(SETTING_NAME);
+ assertFalse(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
+
+ }
+
private SettingsState getSettingStateObject() {
SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e13e49f..8f859b2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -204,7 +204,6 @@
<!-- Permission needed to run network tests in CTS -->
<uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
- <uses-permission android:name="android.permission.NETWORK_STACK" />
<!-- Permission needed to test tcp keepalive offload. -->
<uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
@@ -276,6 +275,9 @@
<!-- Permission needed to test registering pull atom callbacks -->
<uses-permission android:name="android.permission.REGISTER_STATS_PULL_ATOM" />
+ <!-- Permission needed to modify settings overrideable by restore in CTS tests -->
+ <uses-permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 30b461d..da93db7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -147,6 +147,7 @@
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
<uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER" />
<!-- Screen Capturing -->
<uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index cff958f..c036b04 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -12,6 +12,9 @@
"include-annotation": "android.platform.test.scenario.annotation.Scenario"
},
{
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
@@ -28,6 +31,9 @@
"include-annotation": "android.platform.test.scenario.annotation.Scenario"
},
{
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
"exclude-annotation": "androidx.test.filters.FlakyTest"
},
{
diff --git a/packages/SystemUI/res/layout/controls_onboarding.xml b/packages/SystemUI/res/layout/controls_onboarding.xml
new file mode 100644
index 0000000..577a3b4
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_onboarding.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:padding="4dp"
+ android:orientation="vertical">
+
+ <View
+ android:id="@+id/arrow"
+ android:elevation="2dp"
+ android:layout_width="10dp"
+ android:layout_height="8dp"
+ android:layout_marginBottom="-2dp"
+ android:layout_gravity="center_horizontal"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="24dp"
+ android:paddingEnd="4dp"
+ android:background="@drawable/recents_onboarding_toast_rounded_background"
+ android:layout_gravity="center_horizontal"
+ android:elevation="2dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/onboarding_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:textColor="?attr/wallpaperTextColor"
+ android:textSize="16sp"/>
+ <ImageView
+ android:id="@+id/dismiss"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_gravity="center_vertical"
+ android:padding="10dp"
+ android:layout_marginStart="2dp"
+ android:layout_marginEnd="2dp"
+ android:alpha="0.7"
+ android:src="@drawable/ic_close_white"
+ android:tint="?attr/wallpaperTextColor"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/accessibility_desc_close"/>
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_structure_page.xml b/packages/SystemUI/res/layout/controls_structure_page.xml
index 2c7e168..047ab98 100644
--- a/packages/SystemUI/res/layout/controls_structure_page.xml
+++ b/packages/SystemUI/res/layout/controls_structure_page.xml
@@ -15,17 +15,10 @@
~ limitations under the License.
-->
-<androidx.core.widget.NestedScrollView
+<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/listAll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:layout_marginTop="@dimen/controls_management_list_margin">
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/listAll"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
-
-</androidx.core.widget.NestedScrollView>
\ No newline at end of file
+ android:layout_marginTop="@dimen/controls_management_list_margin"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d160829..20cafd0 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -117,7 +117,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,controls,screenrecord
+ wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index caf22fe..18fec29 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2653,4 +2653,7 @@
<string name="controls_pin_verify">Verify device PIN</string>
<!-- Controls PIN entry dialog, text hint [CHAR LIMIT=30] -->
<string name="controls_pin_instructions">Enter PIN</string>
+
+ <!-- Tooltip to show in management screen when there are multiple structures [CHAR_LIMIT=50] -->
+ <string name="controls_structure_tooltip">Swipe to see other structures</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 125dd8f..4770910 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -650,6 +650,7 @@
<!-- Controls styles -->
<style name="Theme.ControlsManagement" parent="@android:style/Theme.DeviceDefault.NoActionBar">
<item name="android:windowIsTranslucent">false</item>
+ <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
</style>
<style name="TextAppearance.Control">
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 1c6223b..9e9b9dc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -37,7 +37,8 @@
public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { }
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
public void onActivityUnpinned() { }
- public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) { }
public void onActivityForcedResizable(String packageName, int taskId, int reason) { }
public void onActivityDismissingDockedStack() { }
public void onActivityLaunchOnSecondaryDisplayFailed() { }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index cbdd3f8..ce9cbab 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -30,6 +30,7 @@
import android.os.Trace;
import android.util.Log;
+import com.android.internal.os.SomeArgs;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.ArrayList;
@@ -120,11 +121,14 @@
}
@Override
- public void onPinnedActivityRestartAttempt(boolean clearedTask)
- throws RemoteException {
- mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
- mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0)
- .sendToTarget();
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) throws RemoteException {
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = task;
+ args.argi1 = homeTaskVisible ? 1 : 0;
+ args.argi2 = clearedTask ? 1 : 0;
+ mHandler.removeMessages(H.ON_ACTIVITY_RESTART_ATTEMPT);
+ mHandler.obtainMessage(H.ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
}
@Override
@@ -236,7 +240,7 @@
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
private static final int ON_ACTIVITY_PINNED = 3;
- private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4;
+ private static final int ON_ACTIVITY_RESTART_ATTEMPT = 4;
private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6;
private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7;
private static final int ON_TASK_PROFILE_LOCKED = 8;
@@ -296,10 +300,14 @@
}
break;
}
- case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
+ case ON_ACTIVITY_RESTART_ATTEMPT: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final RunningTaskInfo task = (RunningTaskInfo) args.arg1;
+ final boolean homeTaskVisible = args.argi1 != 0;
+ final boolean clearedTask = args.argi2 != 0;
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(
- msg.arg1 != 0);
+ mTaskStackListeners.get(i).onActivityRestartAttempt(task,
+ homeTaskVisible, clearedTask);
}
break;
}
@@ -419,6 +427,9 @@
}
}
}
+ if (msg.obj instanceof SomeArgs) {
+ ((SomeArgs) msg.obj).recycle();
+ }
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
index b813e21..7570c2c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
@@ -18,7 +18,11 @@
import android.app.WallpaperManager;
import android.content.Context;
+import android.os.IBinder;
+/**
+ * @see WallpaperManager
+ */
public class WallpaperManagerCompat {
private final WallpaperManager mWallpaperManager;
@@ -26,7 +30,10 @@
mWallpaperManager = context.getSystemService(WallpaperManager.class);
}
- public void setWallpaperZoomOut(float zoom) {
- mWallpaperManager.setWallpaperZoomOut(zoom);
+ /**
+ * @see WallpaperManager#setWallpaperZoomOut(IBinder, float)
+ */
+ public void setWallpaperZoomOut(IBinder windowToken, float zoom) {
+ mWallpaperManager.setWallpaperZoomOut(windowToken, zoom);
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 4508fc7..431c451 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -379,7 +379,7 @@
if (DEBUG_SIM_STATES) {
Log.v(TAG, "onSubscriptionInfoChanged()");
List<SubscriptionInfo> sil = mSubscriptionManager
- .getActiveAndHiddenSubscriptionInfoList();
+ .getCompleteActiveSubscriptionInfoList();
if (sil != null) {
for (SubscriptionInfo subInfo : sil) {
Log.v(TAG, "SubInfo:" + subInfo);
@@ -433,10 +433,10 @@
public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
List<SubscriptionInfo> sil = mSubscriptionInfo;
if (sil == null || forceReload) {
- sil = mSubscriptionManager.getActiveAndHiddenSubscriptionInfoList();
+ sil = mSubscriptionManager.getCompleteActiveSubscriptionInfoList();
}
if (sil == null) {
- // getActiveAndHiddenSubscriptionInfoList was null callers expect an empty list.
+ // getCompleteActiveSubscriptionInfoList was null callers expect an empty list.
mSubscriptionInfo = new ArrayList<SubscriptionInfo>();
} else {
mSubscriptionInfo = sil;
@@ -1086,7 +1086,7 @@
mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
} else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
final Message msg = mHandler.obtainMessage(
- MSG_TIMEZONE_UPDATE, intent.getStringExtra("time-zone"));
+ MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE));
mHandler.sendMessage(msg);
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 0367464..2200b22 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -43,6 +43,7 @@
import com.android.systemui.util.InjectionInflationController;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -74,8 +75,8 @@
private final ContentObserver mContentObserver =
new ContentObserver(mMainHandler) {
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- super.onChange(selfChange, uri, userId);
+ public void onChange(boolean selfChange, Collection<Uri> uris,
+ int flags, int userId) {
if (Objects.equals(userId,
mCurrentUserObservable.getCurrentUser().getValue())) {
reload();
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index a868cf5..b6152da 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -71,12 +71,11 @@
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -289,7 +288,6 @@
@Inject Lazy<NotificationLogger> mNotificationLogger;
@Inject Lazy<NotificationViewHierarchyManager> mNotificationViewHierarchyManager;
@Inject Lazy<NotificationFilter> mNotificationFilter;
- @Inject Lazy<NotificationInterruptionStateProvider> mNotificationInterruptionStateProvider;
@Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
@Inject Lazy<SmartReplyController> mSmartReplyController;
@Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
@@ -489,8 +487,6 @@
mProviders.put(NotificationViewHierarchyManager.class,
mNotificationViewHierarchyManager::get);
mProviders.put(NotificationFilter.class, mNotificationFilter::get);
- mProviders.put(NotificationInterruptionStateProvider.class,
- mNotificationInterruptionStateProvider::get);
mProviders.put(KeyguardDismissUtil.class, mKeyguardDismissUtil::get);
mProviders.put(SmartReplyController.class, mSmartReplyController::get);
mProviders.put(RemoteInputQuickSettingsDisabler.class,
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index dbcdead..23fa645 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -203,6 +203,11 @@
}
}
+ @Override
+ public boolean shouldZoomOutWallpaper() {
+ return true;
+ }
+
private void waitForBackgroundRendering() {
synchronized (mMonitor) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 5e6589f..6aa2326 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -59,7 +59,8 @@
Key.TOUCHED_RINGER_TOGGLE,
Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP,
Key.HAS_SEEN_BUBBLES_EDUCATION,
- Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION
+ Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION,
+ Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
})
public @interface Key {
@Deprecated
@@ -107,6 +108,7 @@
String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip";
String HAS_SEEN_BUBBLES_EDUCATION = "HasSeenBubblesOnboarding";
String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding";
+ String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index cab9f18..537a812 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -48,6 +48,7 @@
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.os.Handler;
@@ -725,7 +726,8 @@
private final Rect mBoundingRect = new Rect();
private final Path mBoundingPath = new Path();
// Don't initialize these yet because they may never exist
- private Rect mProtectionRect;
+ private RectF mProtectionRect;
+ private RectF mProtectionRectOrig;
private Path mProtectionPath;
private Path mProtectionPathOrig;
private Rect mTotalBounds = new Rect();
@@ -818,7 +820,11 @@
mProtectionPath = new Path();
}
mProtectionPathOrig.set(protectionPath);
- mProtectionRect = pathBounds;
+ if (mProtectionRectOrig == null) {
+ mProtectionRectOrig = new RectF();
+ mProtectionRect = new RectF();
+ }
+ mProtectionRectOrig.set(pathBounds);
}
void setShowProtection(boolean shouldShow) {
@@ -898,6 +904,7 @@
// Reset the protection path so we don't aggregate rotations
mProtectionPath.set(mProtectionPathOrig);
mProtectionPath.transform(m);
+ m.mapRect(mProtectionRect, mProtectionRectOrig);
}
}
@@ -964,7 +971,8 @@
if (mShowProtection) {
// Make sure that our measured height encompases the protection
mTotalBounds.union(mBoundingRect);
- mTotalBounds.union(mProtectionRect);
+ mTotalBounds.union((int) mProtectionRect.left, (int) mProtectionRect.top,
+ (int) mProtectionRect.right, (int) mProtectionRect.bottom);
setMeasuredDimension(
resolveSizeAndState(mTotalBounds.width(), widthMeasureSpec, 0),
resolveSizeAndState(mTotalBounds.height(), heightMeasureSpec, 0));
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 22c2c7e..406e7ce 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -83,11 +83,11 @@
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -169,7 +169,7 @@
// Callback that updates BubbleOverflowActivity on data change.
@Nullable private Runnable mOverflowCallback = null;
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private IStatusBarService mBarService;
// Used for determining view rect for touch interaction
@@ -279,7 +279,7 @@
ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
- NotificationInterruptionStateProvider interruptionStateProvider,
+ NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
@@ -304,7 +304,7 @@
BubbleData data,
@Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
ConfigurationController configurationController,
- NotificationInterruptionStateProvider interruptionStateProvider,
+ NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
@@ -316,7 +316,7 @@
dumpManager.registerDumpable(TAG, this);
mContext = context;
mShadeController = shadeController;
- mNotificationInterruptionStateProvider = interruptionStateProvider;
+ mNotificationInterruptStateProvider = interruptionStateProvider;
mNotifUserManager = notifUserManager;
mZenModeController = zenModeController;
mFloatingContentCoordinator = floatingContentCoordinator;
@@ -632,7 +632,7 @@
for (NotificationEntry e :
mNotificationEntryManager.getActiveNotificationsForCurrentUser()) {
if (savedBubbleKeys.contains(e.getKey())
- && mNotificationInterruptionStateProvider.shouldBubbleUp(e)
+ && mNotificationInterruptStateProvider.shouldBubbleUp(e)
&& canLaunchInActivityView(mContext, e)) {
updateBubble(e, /* suppressFlyout= */ true);
}
@@ -894,7 +894,7 @@
boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
mContext, entry, previouslyUserCreated, userBlocked);
- if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+ if (mNotificationInterruptStateProvider.shouldBubbleUp(entry)
&& (canLaunchInActivityView(mContext, entry) || wasAdjusted)) {
if (wasAdjusted && !previouslyUserCreated) {
// Gotta treat the auto-bubbled / whitelisted packaged bubbles as usercreated
@@ -910,7 +910,7 @@
boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
mContext, entry, previouslyUserCreated, userBlocked);
- boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+ boolean shouldBubble = mNotificationInterruptStateProvider.shouldBubbleUp(entry)
&& (canLaunchInActivityView(mContext, entry) || wasAdjusted);
if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) {
// It was previously a bubble but no longer a bubble -- lets remove it
@@ -1227,6 +1227,17 @@
}
@Override
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) {
+ for (Bubble b : mBubbleData.getBubbles()) {
+ if (b.getDisplayId() == task.displayId) {
+ expandStackAndSelectBubble(b.getKey());
+ return;
+ }
+ }
+ }
+
+ @Override
public void onActivityLaunchOnSecondaryDisplayRerouted() {
if (mStackView != null) {
mBubbleData.setExpanded(false);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index e8acbab..0b7dbd2b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -1386,18 +1386,24 @@
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "onBubbleDragStart: bubble=" + bubble);
}
- maybeShowManageEducation(false);
+
+ if (bubble.equals(mBubbleOverflow.getIconView())) {
+ return;
+ }
+
mExpandedAnimationController.prepareForBubbleDrag(bubble, mMagneticTarget);
// We're dragging an individual bubble, so set the magnetized object to the magnetized
// bubble.
mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut();
mMagnetizedObject.setMagnetListener(mIndividualBubbleMagnetListener);
+
+ maybeShowManageEducation(false);
}
/** Called with the coordinates to which an individual bubble has been dragged. */
public void onBubbleDragged(View bubble, float x, float y) {
- if (!mIsExpanded || mIsExpansionAnimating) {
+ if (!mIsExpanded || mIsExpansionAnimating || bubble.equals(mBubbleOverflow.getIconView())) {
return;
}
@@ -1412,7 +1418,7 @@
Log.d(TAG, "onBubbleDragFinish: bubble=" + bubble);
}
- if (!mIsExpanded || mIsExpansionAnimating) {
+ if (!mIsExpanded || mIsExpansionAnimating || bubble.equals(mBubbleOverflow.getIconView())) {
return;
}
@@ -1420,6 +1426,18 @@
hideDismissTarget();
}
+ /** Expands the clicked bubble. */
+ public void expandBubble(Bubble bubble) {
+ if (bubble.equals(mBubbleData.getSelectedBubble())) {
+ // If the bubble we're supposed to expand is the selected bubble, that means the
+ // overflow bubble is currently expanded. Don't tell BubbleData to set this bubble as
+ // selected, since it already is. Just call the stack's setSelectedBubble to expand it.
+ setSelectedBubble(bubble);
+ } else {
+ mBubbleData.setSelectedBubble(bubble);
+ }
+ }
+
void onDragStart() {
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "onDragStart()");
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 0c5bef4..132c45f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -189,7 +189,7 @@
if (key == BubbleOverflow.KEY) {
mStack.showOverflow();
} else {
- mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(key));
+ mStack.expandBubble(mBubbleData.getBubbleWithKey(key));
}
}
resetForNextGesture();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
index ac97d8a..27c9e98 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -25,8 +25,8 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -54,7 +54,7 @@
ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
- NotificationInterruptionStateProvider interruptionStateProvider,
+ NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
index 49a16d8..dec6007 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
@@ -16,10 +16,12 @@
package com.android.systemui.controls
+import android.content.ComponentName
import android.service.controls.Control
data class ControlStatus(
val control: Control,
+ val component: ComponentName,
var favorite: Boolean,
val removed: Boolean = false
-)
\ No newline at end of file
+)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt b/packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt
new file mode 100644
index 0000000..6e17bc9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt
@@ -0,0 +1,160 @@
+/*
+ * 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.systemui.controls
+
+import android.annotation.StringRes
+import android.content.Context
+import android.graphics.CornerPathEffect
+import android.graphics.drawable.ShapeDrawable
+import android.util.TypedValue
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.animation.AccelerateInterpolator
+import android.view.animation.DecelerateInterpolator
+import android.widget.TextView
+import com.android.systemui.Prefs
+import com.android.systemui.R
+import com.android.systemui.recents.TriangleShape
+
+/**
+ * Manager for showing an onboarding tooltip on screen.
+ *
+ * The tooltip can be made to appear below or above a point. The number of times it will appear
+ * is determined by an shared preference (defined in [Prefs]).
+ *
+ * @property context A context to use to inflate the views and retrieve shared preferences from
+ * @property preferenceName name of the preference to use to track the number of times the tooltip
+ * has been shown.
+ * @property maxTimesShown the maximum number of times to show the tooltip
+ * @property below whether the tooltip should appear below (with up pointing arrow) or above (down
+ * pointing arrow) the specified point.
+ * @see [TooltipManager.show]
+ */
+class TooltipManager(
+ context: Context,
+ private val preferenceName: String,
+ private val maxTimesShown: Int = 2,
+ private val below: Boolean = true
+) {
+
+ companion object {
+ private const val SHOW_DELAY_MS: Long = 500
+ private const val SHOW_DURATION_MS: Long = 300
+ private const val HIDE_DURATION_MS: Long = 100
+ }
+
+ private var shown = Prefs.getInt(context, preferenceName, 0)
+
+ val layout: ViewGroup =
+ LayoutInflater.from(context).inflate(R.layout.controls_onboarding, null) as ViewGroup
+ val preferenceStorer = { num: Int ->
+ Prefs.putInt(context, preferenceName, num)
+ }
+
+ init {
+ layout.alpha = 0f
+ }
+
+ private val textView = layout.requireViewById<TextView>(R.id.onboarding_text)
+ private val dismissView = layout.requireViewById<View>(R.id.dismiss).apply {
+ setOnClickListener {
+ hide(true)
+ }
+ }
+
+ private val arrowView = layout.requireViewById<View>(R.id.arrow).apply {
+ val typedValue = TypedValue()
+ context.theme.resolveAttribute(android.R.attr.colorAccent, typedValue, true)
+ val toastColor = context.resources.getColor(typedValue.resourceId, context.theme)
+ val arrowRadius = context.resources.getDimensionPixelSize(
+ R.dimen.recents_onboarding_toast_arrow_corner_radius)
+ val arrowLp = layoutParams
+ val arrowDrawable = ShapeDrawable(TriangleShape.create(
+ arrowLp.width.toFloat(), arrowLp.height.toFloat(), below))
+ val arrowPaint = arrowDrawable.paint
+ arrowPaint.color = toastColor
+ // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
+ arrowPaint.pathEffect = CornerPathEffect(arrowRadius.toFloat())
+ setBackground(arrowDrawable)
+ }
+
+ init {
+ if (!below) {
+ layout.removeView(arrowView)
+ layout.addView(arrowView)
+ (arrowView.layoutParams as ViewGroup.MarginLayoutParams).apply {
+ bottomMargin = topMargin
+ topMargin = 0
+ }
+ }
+ }
+
+ /**
+ * Show the tooltip
+ *
+ * @param stringRes the id of the string to show in the tooltip
+ * @param x horizontal position (w.r.t. screen) for the arrow point
+ * @param y vertical position (w.r.t. screen) for the arrow point
+ */
+ fun show(@StringRes stringRes: Int, x: Int, y: Int) {
+ if (!shouldShow()) return
+ textView.setText(stringRes)
+ shown++
+ preferenceStorer(shown)
+ layout.post {
+ val p = IntArray(2)
+ layout.getLocationOnScreen(p)
+ layout.translationX = (x - p[0] - layout.width / 2).toFloat()
+ layout.translationY = (y - p[1]).toFloat() - if (!below) layout.height else 0
+ if (layout.alpha == 0f) {
+ layout.animate()
+ .alpha(1f)
+ .withLayer()
+ .setStartDelay(SHOW_DELAY_MS)
+ .setDuration(SHOW_DURATION_MS)
+ .setInterpolator(DecelerateInterpolator())
+ .start()
+ }
+ }
+ }
+
+ /**
+ * Hide the tooltip
+ *
+ * @param animate whether to animate the fade out
+ */
+ fun hide(animate: Boolean = false) {
+ if (layout.alpha == 0f) return
+ layout.post {
+ if (animate) {
+ layout.animate()
+ .alpha(0f)
+ .withLayer()
+ .setStartDelay(0)
+ .setDuration(HIDE_DURATION_MS)
+ .setInterpolator(AccelerateInterpolator())
+ .start()
+ } else {
+ layout.animate().cancel()
+ layout.alpha = 0f
+ }
+ }
+ }
+
+ private fun shouldShow() = shown < maxTimesShown
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
index fd6e256..c5af436 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
@@ -38,8 +38,9 @@
*
* @param component The [ComponentName] of the service to bind
* @param callback a callback to return the loaded controls to (or an error).
+ * @return a runnable to cancel the load
*/
- fun bindAndLoad(component: ComponentName, callback: LoadCallback)
+ fun bindAndLoad(component: ComponentName, callback: LoadCallback): Runnable
/**
* Request to bind to the given service.
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index 8f02c25..f8d4a39 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -31,7 +31,6 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Lazy
-import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
import javax.inject.Singleton
@@ -47,8 +46,6 @@
private const val TAG = "ControlsBindingControllerImpl"
}
- private val refreshing = AtomicBoolean(false)
-
private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
override val currentUserId: Int
@@ -56,6 +53,12 @@
private var currentProvider: ControlsProviderLifecycleManager? = null
+ /*
+ * Will track any active subscriber for subscribe/unsubscribe requests coming into
+ * this controller. Only one can be active at any time
+ */
+ private var statefulControlSubscriber: StatefulControlSubscriber? = null
+
private val actionCallbackService = object : IControlsActionCallback.Stub() {
override fun accept(
token: IBinder,
@@ -66,27 +69,6 @@
}
}
- private val subscriberService = object : IControlsSubscriber.Stub() {
- override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
- backgroundExecutor.execute(OnSubscribeRunnable(token, subs))
- }
-
- override fun onNext(token: IBinder, c: Control) {
- if (!refreshing.get()) {
- Log.d(TAG, "Refresh outside of window for token:$token")
- } else {
- backgroundExecutor.execute(OnNextRunnable(token, c))
- }
- }
- override fun onError(token: IBinder, s: String) {
- backgroundExecutor.execute(OnErrorRunnable(token, s))
- }
-
- override fun onComplete(token: IBinder) {
- backgroundExecutor.execute(OnCompleteRunnable(token))
- }
- }
-
@VisibleForTesting
internal open fun createProviderManager(component: ComponentName):
ControlsProviderLifecycleManager {
@@ -94,43 +76,45 @@
context,
backgroundExecutor,
actionCallbackService,
- subscriberService,
currentUser,
component
)
}
private fun retrieveLifecycleManager(component: ComponentName):
- ControlsProviderLifecycleManager? {
+ ControlsProviderLifecycleManager {
if (currentProvider != null && currentProvider?.componentName != component) {
unbind()
}
- if (currentProvider == null) {
- currentProvider = createProviderManager(component)
- }
+ val provider = currentProvider ?: createProviderManager(component)
+ currentProvider = provider
- return currentProvider
+ return provider
}
override fun bindAndLoad(
component: ComponentName,
callback: ControlsBindingController.LoadCallback
- ) {
- retrieveLifecycleManager(component)?.maybeBindAndLoad(LoadSubscriber(callback))
+ ): Runnable {
+ val subscriber = LoadSubscriber(callback)
+ retrieveLifecycleManager(component).maybeBindAndLoad(subscriber)
+ return subscriber.loadCancel()
}
override fun subscribe(structureInfo: StructureInfo) {
- if (refreshing.compareAndSet(false, true)) {
- val provider = retrieveLifecycleManager(structureInfo.componentName)
- provider?.maybeBindAndSubscribe(structureInfo.controls.map { it.controlId })
- }
+ // make sure this has happened. only allow one active subscription
+ unsubscribe()
+
+ statefulControlSubscriber = null
+ val provider = retrieveLifecycleManager(structureInfo.componentName)
+ val scs = StatefulControlSubscriber(lazyController.get(), provider, backgroundExecutor)
+ statefulControlSubscriber = scs
+ provider.maybeBindAndSubscribe(structureInfo.controls.map { it.controlId }, scs)
}
override fun unsubscribe() {
- if (refreshing.compareAndSet(true, false)) {
- currentProvider?.unsubscribe()
- }
+ statefulControlSubscriber?.cancel()
}
override fun action(
@@ -138,20 +122,24 @@
controlInfo: ControlInfo,
action: ControlAction
) {
- retrieveLifecycleManager(componentName)
- ?.maybeBindAndSendAction(controlInfo.controlId, action)
+ if (statefulControlSubscriber == null) {
+ Log.w(TAG, "No actions can occur outside of an active subscription. Ignoring.")
+ } else {
+ retrieveLifecycleManager(componentName)
+ .maybeBindAndSendAction(controlInfo.controlId, action)
+ }
}
override fun bindService(component: ComponentName) {
- retrieveLifecycleManager(component)?.bindService()
+ retrieveLifecycleManager(component).bindService()
}
override fun changeUser(newUser: UserHandle) {
if (newUser == currentUser) return
+ unsubscribe()
unbind()
-
- refreshing.set(false)
+ currentProvider = null
currentUser = newUser
}
@@ -172,8 +160,8 @@
override fun toString(): String {
return StringBuilder(" ControlsBindingController:\n").apply {
- append(" refreshing=${refreshing.get()}\n")
append(" currentUser=$currentUser\n")
+ append(" StatefulControlSubscriber=$statefulControlSubscriber")
append(" Providers=$currentProvider\n")
}.toString()
}
@@ -208,22 +196,6 @@
) : CallbackRunnable(token) {
override fun doRun() {
callback.accept(list)
- provider?.unbindService()
- }
- }
-
- private inner class OnNextRunnable(
- token: IBinder,
- val control: Control
- ) : CallbackRunnable(token) {
- override fun doRun() {
- if (!refreshing.get()) {
- Log.d(TAG, "onRefresh outside of window from:${provider?.componentName}")
- }
-
- provider?.let {
- lazyController.get().refreshStatus(it.componentName, control)
- }
}
}
@@ -232,33 +204,7 @@
val subscription: IControlsSubscription
) : CallbackRunnable(token) {
override fun doRun() {
- if (!refreshing.get()) {
- Log.d(TAG, "onRefresh outside of window from '${provider?.componentName}'")
- }
- provider?.let {
- it.startSubscription(subscription)
- }
- }
- }
-
- private inner class OnCompleteRunnable(
- token: IBinder
- ) : CallbackRunnable(token) {
- override fun doRun() {
- provider?.let {
- Log.i(TAG, "onComplete receive from '${it.componentName}'")
- }
- }
- }
-
- private inner class OnErrorRunnable(
- token: IBinder,
- val error: String
- ) : CallbackRunnable(token) {
- override fun doRun() {
- provider?.let {
- Log.e(TAG, "onError receive from '${it.componentName}': $error")
- }
+ provider?.startSubscription(subscription)
}
}
@@ -292,8 +238,14 @@
) : IControlsSubscriber.Stub() {
val loadedControls = ArrayList<Control>()
var hasError = false
+ private var _loadCancelInternal: (() -> Unit)? = null
+ fun loadCancel() = Runnable {
+ Log.d(TAG, "Cancel load requested")
+ _loadCancelInternal?.invoke()
+ }
override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
+ _loadCancelInternal = subs::cancel
backgroundExecutor.execute(OnSubscribeRunnable(token, subs))
}
@@ -302,11 +254,15 @@
}
override fun onError(token: IBinder, s: String) {
hasError = true
+ _loadCancelInternal = {}
+ currentProvider?.cancelLoadTimeout()
backgroundExecutor.execute(OnLoadErrorRunnable(token, s, callback))
}
override fun onComplete(token: IBinder) {
+ _loadCancelInternal = {}
if (!hasError) {
+ currentProvider?.cancelLoadTimeout()
backgroundExecutor.execute(OnLoadRunnable(token, loadedControls, callback))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index 7eafe2e..9e0d26c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -59,6 +59,11 @@
)
/**
+ * Cancels a pending load call
+ */
+ fun cancelLoad()
+
+ /**
* Request to subscribe for favorited controls per structure
*
* @param structureInfo structure to limit the subscription to
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 5e1ed58..9cb902f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -72,6 +72,8 @@
private var userChanging: Boolean = true
+ private var loadCanceller: Runnable? = null
+
private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
override val currentUserId
get() = currentUser.identifier
@@ -127,7 +129,7 @@
internal val settingObserver = object : ContentObserver(null) {
override fun onChange(
selfChange: Boolean,
- uris: MutableIterable<Uri>,
+ uris: Collection<Uri>,
flags: Int,
userId: Int
) {
@@ -213,8 +215,9 @@
if (!confirmAvailability()) {
if (userChanging) {
// Try again later, userChanging should not last forever. If so, we have bigger
- // problems
- executor.executeDelayed(
+ // problems. This will return a runnable that allows to cancel the delayed version,
+ // it will not be able to cancel the load if
+ loadCanceller = executor.executeDelayed(
{ loadForComponent(componentName, dataCallback) },
USER_CHANGE_RETRY_DELAY,
TimeUnit.MILLISECONDS
@@ -224,10 +227,11 @@
}
return
}
- bindingController.bindAndLoad(
+ loadCanceller = bindingController.bindAndLoad(
componentName,
object : ControlsBindingController.LoadCallback {
override fun accept(controls: List<Control>) {
+ loadCanceller = null
executor.execute {
val favoritesForComponentKeys = Favorites
.getControlsForComponent(componentName).map { it.controlId }
@@ -238,7 +242,11 @@
}
val removed = findRemoved(favoritesForComponentKeys.toSet(), controls)
val controlsWithFavorite = controls.map {
- ControlStatus(it, it.controlId in favoritesForComponentKeys)
+ ControlStatus(
+ it,
+ componentName,
+ it.controlId in favoritesForComponentKeys
+ )
}
val loadData = createLoadDataObject(
Favorites.getControlsForComponent(componentName)
@@ -247,12 +255,12 @@
controlsWithFavorite,
favoritesForComponentKeys
)
-
dataCallback.accept(loadData)
}
}
override fun error(message: String) {
+ loadCanceller = null
executor.execute {
val loadData = Favorites.getControlsForComponent(componentName)
.let { controls ->
@@ -265,7 +273,6 @@
true
)
}
-
dataCallback.accept(loadData)
}
}
@@ -273,6 +280,12 @@
)
}
+ override fun cancelLoad() {
+ loadCanceller?.let {
+ executor.execute(it)
+ }
+ }
+
private fun createRemovedStatus(
componentName: ComponentName,
controlInfo: ControlInfo,
@@ -290,7 +303,7 @@
.setTitle(controlInfo.controlTitle)
.setDeviceType(controlInfo.deviceType)
.build()
- return ControlStatus(control, true, setRemoved)
+ return ControlStatus(control, componentName, true, setRemoved)
}
private fun findRemoved(favoriteKeys: Set<String>, list: List<Control>): Set<String> {
@@ -489,10 +502,12 @@
updatedStructure
} else { s }
- structures.add(newStructure)
+ if (!newStructure.controls.isEmpty()) {
+ structures.add(newStructure)
+ }
}
- if (!replaced) {
+ if (!replaced && !updatedStructure.controls.isEmpty()) {
structures.add(updatedStructure)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 86e8e83..4918bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -58,7 +58,6 @@
private val context: Context,
private val executor: DelayableExecutor,
private val actionCallbackService: IControlsActionCallback.Stub,
- private val subscriberService: IControlsSubscriber.Stub,
val user: UserHandle,
val componentName: ComponentName
) : IBinder.DeathRecipient {
@@ -157,10 +156,9 @@
load(msg.subscriber)
}
- queue.filter { it is Message.Subscribe }.flatMap { (it as Message.Subscribe).list }.run {
- if (this.isNotEmpty()) {
- subscribe(this)
- }
+ queue.filter { it is Message.Subscribe }.forEach {
+ val msg = it as Message.Subscribe
+ subscribe(msg.list, msg.subscriber)
}
queue.filter { it is Message.Action }.forEach {
val msg = it as Message.Action
@@ -185,9 +183,9 @@
}
}
- private fun unqueueMessage(message: Message) {
+ private fun unqueueMessageType(type: Int) {
synchronized(queuedMessages) {
- queuedMessages.removeIf { it.type == message.type }
+ queuedMessages.removeIf { it.type == type }
}
}
@@ -219,7 +217,7 @@
* @param subscriber the subscriber that manages coordination for loading controls
*/
fun maybeBindAndLoad(subscriber: IControlsSubscriber.Stub) {
- unqueueMessage(Message.Unbind)
+ unqueueMessageType(MSG_UNBIND)
onLoadCanceller = executor.executeDelayed({
// Didn't receive a response in time, log and send back error
Log.d(TAG, "Timeout waiting onLoad for $componentName")
@@ -230,6 +228,11 @@
invokeOrQueue({ load(subscriber) }, Message.Load(subscriber))
}
+ fun cancelLoadTimeout() {
+ onLoadCanceller?.run()
+ onLoadCanceller = null
+ }
+
/**
* Request a subscription to the [Publisher] returned by [ControlsProviderService.publisherFor]
*
@@ -237,16 +240,20 @@
*
* @param controlIds a list of the ids of controls to send status back.
*/
- fun maybeBindAndSubscribe(controlIds: List<String>) {
- invokeOrQueue({ subscribe(controlIds) }, Message.Subscribe(controlIds))
+ fun maybeBindAndSubscribe(controlIds: List<String>, subscriber: IControlsSubscriber) {
+ invokeOrQueue(
+ { subscribe(controlIds, subscriber) },
+ Message.Subscribe(controlIds, subscriber)
+ )
}
- private fun subscribe(controlIds: List<String>) {
+ private fun subscribe(controlIds: List<String>, subscriber: IControlsSubscriber) {
if (DEBUG) {
Log.d(TAG, "subscribe $componentName - $controlIds")
}
- if (!(wrapper?.subscribe(controlIds, subscriberService) ?: false)) {
- queueMessage(Message.Subscribe(controlIds))
+
+ if (!(wrapper?.subscribe(controlIds, subscriber) ?: false)) {
+ queueMessage(Message.Subscribe(controlIds, subscriber))
binderDied()
}
}
@@ -276,10 +283,13 @@
/**
* Starts the subscription to the [ControlsProviderService] and requests status of controls.
*
- * @param subscription the subscriber to use to request controls
+ * @param subscription the subscription to use to request controls
* @see maybeBindAndLoad
*/
fun startSubscription(subscription: IControlsSubscription) {
+ if (DEBUG) {
+ Log.d(TAG, "startSubscription: $subscription")
+ }
synchronized(subscriptions) {
subscriptions.add(subscription)
}
@@ -287,30 +297,26 @@
}
/**
- * Unsubscribe from this service, cancelling all status requests.
+ * Cancels the subscription to the [ControlsProviderService].
+ *
+ * @param subscription the subscription to cancel
+ * @see maybeBindAndLoad
*/
- fun unsubscribe() {
+ fun cancelSubscription(subscription: IControlsSubscription) {
if (DEBUG) {
- Log.d(TAG, "unsubscribe $componentName")
+ Log.d(TAG, "cancelSubscription: $subscription")
}
- unqueueMessage(Message.Subscribe(emptyList())) // Removes all subscribe messages
-
- val subs = synchronized(subscriptions) {
- ArrayList(subscriptions).also {
- subscriptions.clear()
- }
+ synchronized(subscriptions) {
+ subscriptions.remove(subscription)
}
-
- subs.forEach {
- wrapper?.cancel(it)
- }
+ wrapper?.cancel(subscription)
}
/**
* Request bind to the service.
*/
fun bindService() {
- unqueueMessage(Message.Unbind)
+ unqueueMessageType(MSG_UNBIND)
bindService(true)
}
@@ -321,8 +327,16 @@
onLoadCanceller?.run()
onLoadCanceller = null
- // just in case this wasn't called already
- unsubscribe()
+ // be sure to cancel all subscriptions
+ val subs = synchronized(subscriptions) {
+ ArrayList(subscriptions).also {
+ subscriptions.clear()
+ }
+ }
+
+ subs.forEach {
+ wrapper?.cancel(it)
+ }
bindService(false)
}
@@ -346,7 +360,7 @@
object Unbind : Message() {
override val type = MSG_UNBIND
}
- class Subscribe(val list: List<String>) : Message() {
+ class Subscribe(val list: List<String>, val subscriber: IControlsSubscriber) : Message() {
override val type = MSG_SUBSCRIBE
}
class Action(val id: String, val action: ControlAction) : Message() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt
new file mode 100644
index 0000000..a371aa6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt
@@ -0,0 +1,96 @@
+/*
+ * 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.systemui.controls.controller
+
+import android.os.IBinder
+import android.service.controls.Control
+import android.service.controls.IControlsSubscriber
+import android.service.controls.IControlsSubscription
+import android.util.Log
+import com.android.systemui.util.concurrency.DelayableExecutor
+
+/**
+ * A single subscriber, supporting stateful controls for publishers created by
+ * {@link ControlsProviderService#createPublisherFor}. In general, this subscription will remain
+ * active until the SysUi chooses to cancel it.
+ */
+class StatefulControlSubscriber(
+ private val controller: ControlsController,
+ private val provider: ControlsProviderLifecycleManager,
+ private val bgExecutor: DelayableExecutor
+) : IControlsSubscriber.Stub() {
+ private var subscriptionOpen = false
+ private var subscription: IControlsSubscription? = null
+
+ companion object {
+ private const val TAG = "StatefulControlSubscriber"
+ }
+
+ private fun run(token: IBinder, f: () -> Unit) {
+ if (provider.token == token) {
+ bgExecutor.execute { f() }
+ }
+ }
+
+ override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
+ run(token) {
+ subscriptionOpen = true
+ subscription = subs
+ provider.startSubscription(subs)
+ }
+ }
+
+ override fun onNext(token: IBinder, control: Control) {
+ run(token) {
+ if (!subscriptionOpen) {
+ Log.w(TAG, "Refresh outside of window for token:$token")
+ } else {
+ controller.refreshStatus(provider.componentName, control)
+ }
+ }
+ }
+ override fun onError(token: IBinder, error: String) {
+ run(token) {
+ if (subscriptionOpen) {
+ subscriptionOpen = false
+ Log.e(TAG, "onError receive from '${provider.componentName}': $error")
+ }
+ }
+ }
+
+ override fun onComplete(token: IBinder) {
+ run(token) {
+ if (subscriptionOpen) {
+ subscriptionOpen = false
+ Log.i(TAG, "onComplete receive from '${provider.componentName}'")
+ }
+ }
+ }
+
+ fun cancel() {
+ if (!subscriptionOpen) return
+ bgExecutor.execute {
+ if (subscriptionOpen) {
+ subscriptionOpen = false
+ subscription?.let {
+ provider.cancelSubscription(it)
+ }
+ subscription = null
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
index 179e9fb..563c2f6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt
@@ -16,8 +16,8 @@
package com.android.systemui.controls.management
+import android.content.ComponentName
import android.graphics.Rect
-import android.graphics.drawable.Icon
import android.service.controls.DeviceTypes
import android.view.LayoutInflater
import android.view.View
@@ -147,7 +147,7 @@
override fun bindData(wrapper: ElementWrapper) {
wrapper as ControlWrapper
val data = wrapper.controlStatus
- val renderInfo = getRenderInfo(data.control.deviceType)
+ val renderInfo = getRenderInfo(data.component, data.control.deviceType)
title.text = data.control.title
subtitle.text = data.control.subtitle
favorite.isChecked = data.favorite
@@ -160,16 +160,17 @@
}
private fun getRenderInfo(
+ component: ComponentName,
@DeviceTypes.DeviceType deviceType: Int
): RenderInfo {
- return RenderInfo.lookup(deviceType, true)
+ return RenderInfo.lookup(itemView.context, component, deviceType, true)
}
private fun applyRenderInfo(ri: RenderInfo) {
val context = itemView.context
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
- icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
+ icon.setImageDrawable(ri.icon)
icon.setImageTintList(fg)
}
}
@@ -191,4 +192,4 @@
right = sideMargins
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 04715ab..f2303e6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -19,22 +19,27 @@
import android.app.Activity
import android.content.ComponentName
import android.content.Intent
+import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.text.TextUtils
+import android.view.Gravity
import android.view.View
+import android.view.ViewGroup
import android.view.ViewStub
import android.widget.Button
+import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.viewpager2.widget.ViewPager2
+import com.android.systemui.Prefs
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.controls.TooltipManager
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.qs.PageIndicator
import com.android.systemui.settings.CurrentUserTracker
import java.text.Collator
import java.util.concurrent.Executor
@@ -51,6 +56,8 @@
companion object {
private const val TAG = "ControlsFavoritingActivity"
const val EXTRA_APP = "extra_app_label"
+ private const val TOOLTIP_PREFS_KEY = Prefs.Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
+ private const val TOOLTIP_MAX_SHOWN = 2
}
private var component: ComponentName? = null
@@ -61,7 +68,9 @@
private lateinit var titleView: TextView
private lateinit var iconView: ImageView
private lateinit var iconFrame: View
- private lateinit var pageIndicator: PageIndicator
+ private lateinit var pageIndicator: ManagementPageIndicator
+ private var mTooltipManager: TooltipManager? = null
+ private lateinit var doneButton: View
private var listOfStructures = emptyList<StructureContainer>()
private lateinit var comparator: Comparator<StructureContainer>
@@ -129,6 +138,7 @@
StructureContainer(it.key, AllModel(it.value, favoriteKeys, emptyZoneString))
}.sortedWith(comparator)
executor.execute {
+ doneButton.isEnabled = true
structurePager.adapter = StructureAdapter(listOfStructures)
if (error) {
statusText.text = resources.getText(R.string.controls_favorite_load_error)
@@ -174,7 +184,47 @@
}
statusText = requireViewById(R.id.status_message)
- pageIndicator = requireViewById(R.id.structure_page_indicator)
+ if (shouldShowTooltip()) {
+ mTooltipManager = TooltipManager(statusText.context,
+ TOOLTIP_PREFS_KEY, TOOLTIP_MAX_SHOWN)
+ addContentView(
+ mTooltipManager?.layout,
+ FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ Gravity.TOP or Gravity.LEFT
+ )
+ )
+ }
+ pageIndicator = requireViewById<ManagementPageIndicator>(
+ R.id.structure_page_indicator).apply {
+ addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
+ override fun onLayoutChange(
+ v: View,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ if (v.visibility == View.VISIBLE && mTooltipManager != null) {
+ val p = IntArray(2)
+ v.getLocationOnScreen(p)
+ val x = p[0] + (right - left) / 2
+ val y = p[1] + bottom - top
+ mTooltipManager?.show(R.string.controls_structure_tooltip, x, y)
+ }
+ }
+ })
+ visibilityListener = {
+ if (it != View.VISIBLE) {
+ mTooltipManager?.hide(true)
+ }
+ }
+ }
titleView = requireViewById<TextView>(R.id.title).apply {
text = appName ?: resources.getText(R.string.controls_favorite_default_title)
@@ -184,6 +234,12 @@
iconView = requireViewById(com.android.internal.R.id.icon)
iconFrame = requireViewById(R.id.icon_frame)
structurePager = requireViewById<ViewPager2>(R.id.structure_pager)
+ structurePager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
+ override fun onPageSelected(position: Int) {
+ super.onPageSelected(position)
+ mTooltipManager?.hide(true)
+ }
+ })
bindButtons()
}
@@ -195,23 +251,41 @@
}
}
- requireViewById<Button>(R.id.done).setOnClickListener {
- if (component == null) return@setOnClickListener
- listOfStructures.forEach {
- val favoritesForStorage = it.model.favorites.map { it.build() }
- controller.replaceFavoritesForStructure(StructureInfo(component!!, it.structureName,
- favoritesForStorage))
+ doneButton = requireViewById<Button>(R.id.done).apply {
+ isEnabled = false
+ setOnClickListener {
+ if (component == null) return@setOnClickListener
+ listOfStructures.forEach {
+ val favoritesForStorage = it.model.favorites.map { it.build() }
+ controller.replaceFavoritesForStructure(
+ StructureInfo(component!!, it.structureName, favoritesForStorage)
+ )
+ }
+ finishAffinity()
}
-
- finishAffinity()
}
}
+ override fun onPause() {
+ super.onPause()
+ mTooltipManager?.hide(false)
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ mTooltipManager?.hide(false)
+ }
+
override fun onDestroy() {
currentUserTracker.stopTracking()
listingController.removeCallback(listingCallback)
+ controller.cancelLoad()
super.onDestroy()
}
+
+ private fun shouldShowTooltip(): Boolean {
+ return Prefs.getInt(applicationContext, TOOLTIP_PREFS_KEY, 0) < TOOLTIP_MAX_SHOWN
+ }
}
data class StructureContainer(val structureName: CharSequence, val model: ControlsModel)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 9b108cf..94487e5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -88,6 +88,8 @@
init {
serviceListing.addCallback(serviceListingCallback)
+ serviceListing.setListening(true)
+ serviceListing.reload()
}
override fun changeUser(newUser: UserHandle) {
@@ -95,11 +97,12 @@
callbacks.clear()
availableServices = emptyList()
serviceListing.setListening(false)
- serviceListing.removeCallback(serviceListingCallback)
currentUserId = newUser.identifier
val contextForUser = context.createContextAsUser(newUser, 0)
serviceListing = serviceListingBuilder(contextForUser)
serviceListing.addCallback(serviceListingCallback)
+ serviceListing.setListening(true)
+ serviceListing.reload()
}
}
@@ -118,12 +121,7 @@
backgroundExecutor.execute {
Log.d(TAG, "Subscribing callback")
callbacks.add(listener)
- if (callbacks.size == 1) {
- serviceListing.setListening(true)
- serviceListing.reload()
- } else {
- listener.onServicesUpdated(getCurrentServices())
- }
+ listener.onServicesUpdated(getCurrentServices())
}
}
@@ -136,9 +134,6 @@
backgroundExecutor.execute {
Log.d(TAG, "Unsubscribing callback")
callbacks.remove(listener)
- if (callbacks.size == 0) {
- serviceListing.setListening(false)
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
index 463632b..a7fc2ac8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestDialog.kt
@@ -21,7 +21,6 @@
import android.content.ComponentName
import android.content.DialogInterface
import android.content.Intent
-import android.graphics.drawable.Icon
import android.os.Bundle
import android.os.UserHandle
import android.service.controls.Control
@@ -137,11 +136,10 @@
}
fun createDialog(label: CharSequence): Dialog {
-
- val renderInfo = RenderInfo.lookup(control.deviceType, true)
+ val renderInfo = RenderInfo.lookup(this, component, control.deviceType, true)
val frame = LayoutInflater.from(this).inflate(R.layout.controls_dialog, null).apply {
requireViewById<ImageView>(R.id.icon).apply {
- setImageIcon(Icon.createWithResource(context, renderInfo.iconResourceId))
+ setImageDrawable(renderInfo.icon)
setImageTintList(
context.resources.getColorStateList(renderInfo.foreground, context.theme))
}
@@ -176,4 +174,4 @@
}
finish()
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
index 4289274..72b1098 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
@@ -40,4 +40,13 @@
super.setLocation(location)
}
}
+
+ var visibilityListener: (Int) -> Unit = {}
+
+ override fun onVisibilityChanged(changedView: View, visibility: Int) {
+ super.onVisibilityChanged(changedView, visibility)
+ if (changedView == this) {
+ visibilityListener(visibility)
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
index eb84a8b..680d006 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt
@@ -20,6 +20,7 @@
import android.content.Intent
import android.provider.Settings
import android.service.controls.actions.BooleanAction
+import android.service.controls.actions.CommandAction
import android.util.Log
import android.view.HapticFeedbackConstants
@@ -36,6 +37,10 @@
cvh.clipLayer.setLevel(nextLevel)
}
+ fun touch(cvh: ControlViewHolder, templateId: String) {
+ cvh.action(CommandAction(templateId))
+ }
+
fun longPress(cvh: ControlViewHolder) {
// Long press snould only be called when there is valid control state, otherwise ignore
cvh.cws.control?.let {
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 b1b98bc..fc5663f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -19,11 +19,11 @@
import android.content.Context
import android.graphics.BlendMode
import android.graphics.drawable.ClipDrawable
-import android.graphics.drawable.Icon
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
import android.service.controls.actions.ControlAction
import android.service.controls.templates.ControlTemplate
+import android.service.controls.templates.StatelessTemplate
import android.service.controls.templates.TemperatureControlTemplate
import android.service.controls.templates.ToggleRangeTemplate
import android.service.controls.templates.ToggleTemplate
@@ -122,19 +122,25 @@
return when {
status == Control.STATUS_UNKNOWN -> UnknownBehavior::class
template is ToggleTemplate -> ToggleBehavior::class
+ template is StatelessTemplate -> TouchBehavior::class
template is ToggleRangeTemplate -> ToggleRangeBehavior::class
template is TemperatureControlTemplate -> TemperatureControlBehavior::class
else -> DefaultBehavior::class
}
}
- internal fun applyRenderInfo(ri: RenderInfo) {
+ internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0) {
+ setEnabled(enabled)
+
+ val deviceType = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType
+ val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset)
+
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
val bg = context.getResources().getColorStateList(ri.background, context.getTheme())
status.setTextColor(fg)
statusExtra.setTextColor(fg)
- icon.setImageIcon(Icon.createWithResource(context, ri.iconResourceId))
+ icon.setImageDrawable(ri.icon)
icon.setImageTintList(fg)
clipLayer.getDrawable().apply {
@@ -143,7 +149,7 @@
}
}
- fun setEnabled(enabled: Boolean) {
+ private fun setEnabled(enabled: Boolean) {
status.setEnabled(enabled)
icon.setEnabled(enabled)
}
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 826618a..bde966c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -188,36 +188,23 @@
parent.removeAllViews()
controlViewsById.clear()
- val inflater = LayoutInflater.from(context)
- inflater.inflate(R.layout.controls_with_favorites, parent, true)
+ createListView()
+ createDropDown(items)
+ }
- val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
- var lastRow: ViewGroup = createRow(inflater, listView)
- selectedStructure.controls.forEach {
- if (lastRow.getChildCount() == 2) {
- lastRow = createRow(inflater, listView)
- }
- val item = inflater.inflate(
- R.layout.controls_base_item, lastRow, false) as ViewGroup
- lastRow.addView(item)
- val cvh = ControlViewHolder(item, controlsController.get(), uiExecutor, bgExecutor)
- val key = ControlKey(selectedStructure.componentName, it.controlId)
- cvh.bindData(controlsById.getValue(key))
- controlViewsById.put(key, cvh)
- }
-
- // add spacer if necessary to keep control size consistent
- if ((selectedStructure.controls.size % 2) == 1) {
- lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
+ private fun createDropDown(items: List<SelectionItem>) {
+ items.forEach {
+ RenderInfo.registerComponentIcon(it.componentName, it.icon)
}
val itemsByComponent = items.associateBy { it.componentName }
- var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
- val listItems = allStructures.mapNotNull {
- itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
- }
+ val itemsWithStructure = allStructures.mapNotNull {
+ itemsByComponent.get(it.componentName)?.copy(structure = it.structure)
+ }
+ val selectionItem = findSelectionItem(selectedStructure, itemsWithStructure) ?: items[0]
- addAll(listItems + addControlsItem)
+ var adapter = ItemAdapter(context, R.layout.controls_spinner_item).apply {
+ addAll(itemsWithStructure + addControlsItem)
}
/*
@@ -225,16 +212,15 @@
* for this dialog. Use a textView with the ListPopupWindow to achieve
* a similar effect
*/
- val item = adapter.findSelectionItem(selectedStructure) ?: adapter.getItem(0)
parent.requireViewById<TextView>(R.id.app_or_structure_spinner).apply {
- setText(item.getTitle())
+ setText(selectionItem.getTitle())
// override the default color on the dropdown drawable
(getBackground() as LayerDrawable).getDrawable(1)
.setTint(context.resources.getColor(R.color.control_spinner_dropdown, null))
}
parent.requireViewById<ImageView>(R.id.app_icon).apply {
- setContentDescription(item.getTitle())
- setImageDrawable(item.icon)
+ setContentDescription(selectionItem.getTitle())
+ setImageDrawable(selectionItem.icon)
}
val anchor = parent.requireViewById<ViewGroup>(R.id.controls_header)
anchor.setOnClickListener(object : View.OnClickListener {
@@ -272,6 +258,36 @@
})
}
+ private fun createListView() {
+ val inflater = LayoutInflater.from(context)
+ inflater.inflate(R.layout.controls_with_favorites, parent, true)
+
+ val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup
+ var lastRow: ViewGroup = createRow(inflater, listView)
+ selectedStructure.controls.forEach {
+ if (lastRow.getChildCount() == 2) {
+ lastRow = createRow(inflater, listView)
+ }
+ val baseLayout = inflater.inflate(
+ R.layout.controls_base_item, lastRow, false) as ViewGroup
+ lastRow.addView(baseLayout)
+ val cvh = ControlViewHolder(
+ baseLayout,
+ controlsController.get(),
+ uiExecutor,
+ bgExecutor
+ )
+ val key = ControlKey(selectedStructure.componentName, it.controlId)
+ cvh.bindData(controlsById.getValue(key))
+ controlViewsById.put(key, cvh)
+ }
+
+ // add spacer if necessary to keep control size consistent
+ if ((selectedStructure.controls.size % 2) == 1) {
+ lastRow.addView(Space(context), LinearLayout.LayoutParams(0, 0, 1f))
+ }
+ }
+
private fun loadPreference(structures: List<StructureInfo>): StructureInfo {
if (structures.isEmpty()) return EMPTY_STRUCTURE
@@ -320,6 +336,8 @@
controlsById.clear()
controlViewsById.clear()
controlsListingController.get().removeCallback(listingCallback)
+
+ RenderInfo.clearCache()
}
override fun onRefreshState(componentName: ComponentName, controls: List<Control>) {
@@ -358,6 +376,11 @@
listView.addView(row)
return row
}
+
+ private fun findSelectionItem(si: StructureInfo, items: List<SelectionItem>): SelectionItem? =
+ items.firstOrNull {
+ it.componentName == si.componentName && it.structure == si.structure
+ }
}
private data class SelectionItem(
@@ -388,17 +411,4 @@
}
return view
}
-
- fun findSelectionItem(si: StructureInfo): SelectionItem? {
- var i = 0
- while (i < getCount()) {
- val item = getItem(i)
- if (item.componentName == si.componentName &&
- item.structure == si.structure) {
- return item
- }
- i++
- }
- return null
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
index 1747929..e850a6a 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DefaultBehavior.kt
@@ -25,7 +25,6 @@
override fun bind(cws: ControlWithState) {
cvh.status.setText(cws.control?.getStatusText() ?: "")
- cvh.setEnabled(false)
- cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false))
+ cvh.applyRenderInfo(false)
}
}
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 da52c6f..56267be 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -16,8 +16,14 @@
package com.android.systemui.controls.ui
+import android.annotation.MainThread
+import android.content.ComponentName
+import android.content.Context
+import android.graphics.drawable.Drawable
import android.service.controls.DeviceTypes
import android.service.controls.templates.TemperatureControlTemplate
+import android.util.ArrayMap
+import android.util.SparseArray
import com.android.systemui.R
@@ -31,18 +37,54 @@
}
}
-data class RenderInfo(val iconResourceId: Int, val foreground: Int, val background: Int) {
+data class RenderInfo(val icon: Drawable, val foreground: Int, val background: Int) {
companion object {
- fun lookup(deviceType: Int, enabled: Boolean): RenderInfo {
- val iconState = deviceIconMap.getValue(deviceType)
+ const val APP_ICON_ID = -1
+ private val iconMap = SparseArray<Drawable>()
+ private val appIconMap = ArrayMap<ComponentName, Drawable>()
+
+ @MainThread
+ fun lookup(
+ context: Context,
+ componentName: ComponentName,
+ deviceType: Int,
+ enabled: Boolean,
+ offset: Int = 0
+ ): RenderInfo {
val (fg, bg) = deviceColorMap.getValue(deviceType)
- return RenderInfo(iconState[enabled], fg, bg)
+
+ val iconKey = if (offset > 0) {
+ deviceType * BUCKET_SIZE + offset
+ } else deviceType
+
+ val iconState = deviceIconMap.getValue(iconKey)
+ val resourceId = iconState[enabled]
+ var icon: Drawable? = null
+ if (resourceId == APP_ICON_ID) {
+ icon = appIconMap.get(componentName)
+ if (icon == null) {
+ icon = context.resources
+ .getDrawable(R.drawable.ic_device_unknown_gm2_24px, null)
+ appIconMap.put(componentName, icon)
+ }
+ } else {
+ icon = iconMap.get(resourceId)
+ if (icon == null) {
+ icon = context.resources.getDrawable(resourceId, null)
+ iconMap.put(resourceId, icon)
+ }
+ }
+ return RenderInfo(icon!!, fg, bg)
}
- fun lookup(deviceType: Int, offset: Int, enabled: Boolean): RenderInfo {
- val key = deviceType * BUCKET_SIZE + offset
- return lookup(key, enabled)
+ fun registerComponentIcon(componentName: ComponentName, icon: Drawable) {
+ appIconMap.put(componentName, icon)
+ }
+
+ fun clearCache() {
+ iconMap.clear()
+ appIconMap.clear()
}
}
}
@@ -116,6 +158,10 @@
DeviceTypes.TYPE_MOP to IconState(
R.drawable.ic_vacuum_gm2_24px,
R.drawable.ic_vacuum_gm2_24px
+ ),
+ DeviceTypes.TYPE_ROUTINE to IconState(
+ RenderInfo.APP_ICON_ID,
+ RenderInfo.APP_ICON_ID
)
).withDefault {
IconState(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
index 239d2e5..15c1dab 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt
@@ -47,10 +47,7 @@
val activeMode = template.getCurrentActiveMode()
val enabled = activeMode != 0 && activeMode != TemperatureControlTemplate.MODE_OFF
- val deviceType = control.getDeviceType()
-
clipLayer.setLevel(if (enabled) MAX_LEVEL else MIN_LEVEL)
- cvh.setEnabled(enabled)
- cvh.applyRenderInfo(RenderInfo.lookup(deviceType, activeMode, enabled))
+ cvh.applyRenderInfo(enabled, activeMode)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
index d306d7c..a3368ef 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleBehavior.kt
@@ -34,7 +34,7 @@
override fun initialize(cvh: ControlViewHolder) {
this.cvh = cvh
- cvh.setEnabled(false)
+ cvh.applyRenderInfo(false)
cvh.layout.setOnClickListener(View.OnClickListener() {
ControlActionCoordinator.toggle(cvh, template.getTemplateId(), template.isChecked())
@@ -51,10 +51,7 @@
clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
val checked = template.isChecked()
- val deviceType = control.getDeviceType()
-
clipLayer.setLevel(if (checked) MAX_LEVEL else MIN_LEVEL)
- cvh.setEnabled(checked)
- cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked))
+ cvh.applyRenderInfo(checked)
}
}
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 cca56c2..6595b55 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -56,7 +56,7 @@
status = cvh.status
context = status.getContext()
- cvh.setEnabled(false)
+ cvh.applyRenderInfo(false)
val gestureListener = ToggleRangeGestureListener(cvh.layout)
val gestureDetector = GestureDetector(context, gestureListener)
@@ -89,14 +89,11 @@
rangeTemplate = template.getRange()
val checked = template.isChecked()
- val deviceType = control.getDeviceType()
-
val currentRatio = rangeTemplate.getCurrentValue() /
(rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
updateRange(currentRatio, checked)
- cvh.setEnabled(checked)
- cvh.applyRenderInfo(RenderInfo.lookup(deviceType, checked))
+ cvh.applyRenderInfo(checked)
}
fun beginUpdateRange() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
new file mode 100644
index 0000000..d64a5f0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt
@@ -0,0 +1,58 @@
+/*
+ * 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.systemui.controls.ui
+
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.LayerDrawable
+import android.view.View
+import android.service.controls.Control
+import android.service.controls.templates.StatelessTemplate
+
+import com.android.systemui.R
+import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL
+
+/**
+ * Supports touch events, but has no notion of state as the {@link ToggleBehavior} does. Must be
+ * used with {@link StatelessTemplate}.
+ */
+class TouchBehavior : Behavior {
+ lateinit var clipLayer: Drawable
+ lateinit var template: StatelessTemplate
+ lateinit var control: Control
+ lateinit var cvh: ControlViewHolder
+
+ override fun initialize(cvh: ControlViewHolder) {
+ this.cvh = cvh
+ cvh.applyRenderInfo(false)
+
+ cvh.layout.setOnClickListener(View.OnClickListener() {
+ ControlActionCoordinator.touch(cvh, template.getTemplateId())
+ })
+ }
+
+ override fun bind(cws: ControlWithState) {
+ this.control = cws.control!!
+ cvh.status.setText(control.getStatusText())
+ template = control.getControlTemplate() as StatelessTemplate
+
+ val ld = cvh.layout.getBackground() as LayerDrawable
+ clipLayer = ld.findDrawableByLayerId(R.id.clip_layer)
+ clipLayer.setLevel(MIN_LEVEL)
+
+ cvh.applyRenderInfo(false)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt
index 1f33b85..c357249 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/UnknownBehavior.kt
@@ -25,7 +25,6 @@
override fun bind(cws: ControlWithState) {
cvh.status.setText(cvh.context.getString(com.android.internal.R.string.loading))
- cvh.setEnabled(false)
- cvh.applyRenderInfo(RenderInfo.lookup(cws.ci.deviceType, false))
+ cvh.applyRenderInfo(false)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 2877ed0..5b3d5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -44,8 +44,6 @@
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
import com.android.systemui.statusbar.policy.CastController;
@@ -179,12 +177,6 @@
/**
*/
@Binds
- public abstract BatteryController provideBatteryController(
- BatteryControllerImpl controllerImpl);
-
- /**
- */
- @Binds
public abstract ManagedProfileController provideManagedProfileController(
ManagedProfileControllerImpl controllerImpl);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 6c502d2..3a4b273 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -90,7 +90,7 @@
/** */
@Provides
- public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
+ public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) {
return new AmbientDisplayConfiguration(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index b4e5125..956b4aa 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -43,6 +43,8 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.ShadeControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
@@ -78,6 +80,11 @@
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
@Binds
+ @Singleton
+ public abstract BatteryController provideBatteryController(
+ BatteryControllerImpl controllerImpl);
+
+ @Binds
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 513580f..2e9ce12 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.view.Choreographer;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.BootCompleteCache;
@@ -31,22 +30,16 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.Recents;
import com.android.systemui.stackdivider.Divider;
-import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.NotificationShadeWindowBlurController;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
-import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
-import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.ConcurrencyModule;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.time.SystemClock;
@@ -98,21 +91,6 @@
keyguardUpdateMonitor, dumpManager);
}
- @Singleton
- @Provides
- @Nullable
- static NotificationShadeWindowBlurController providesBlurController(BlurUtils blurUtils,
- SysuiStatusBarStateController statusBarStateController,
- DumpManager dumpManager, BiometricUnlockController biometricUnlockController,
- KeyguardStateController keyguardStateController,
- NotificationShadeWindowController notificationShadeWindowController,
- Choreographer choreographer) {
- return blurUtils.supportsBlursOnWindows() ? new NotificationShadeWindowBlurController(
- statusBarStateController, blurUtils, biometricUnlockController,
- keyguardStateController, notificationShadeWindowController, choreographer,
- dumpManager) : null;
- }
-
/** */
@Binds
public abstract NotificationRowBinder bindNotificationRowBinder(
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index c28a719..700a861 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -49,6 +49,7 @@
import com.android.systemui.util.wakelock.WakeLock;
import java.io.PrintWriter;
+import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
@@ -261,7 +262,7 @@
private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
- public void onChange(boolean selfChange, Iterable<Uri> uris, int flags, int userId) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
if (userId != ActivityManager.getCurrentUser()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 786ad2c..27c81ce 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1793,7 +1793,7 @@
int alpha = (int) (animatedValue * mScrimAlpha * 255);
mBackgroundDrawable.setAlpha(alpha);
mBlurUtils.applyBlur(mGlobalActionsLayout.getViewRootImpl(),
- mBlurUtils.radiusForRatio(animatedValue));
+ mBlurUtils.blurRadiusOfRatio(animatedValue));
})
.start();
if (mControlsUiController != null) {
@@ -1823,7 +1823,7 @@
int alpha = (int) (animatedValue * mScrimAlpha * 255);
mBackgroundDrawable.setAlpha(alpha);
mBlurUtils.applyBlur(mGlobalActionsLayout.getViewRootImpl(),
- mBlurUtils.radiusForRatio(animatedValue));
+ mBlurUtils.blurRadiusOfRatio(animatedValue));
})
.start();
dismissPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 280a248..bbb57bd 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -151,7 +151,7 @@
if (mBlurUtils.supportsBlursOnWindows()) {
background.setAlpha((int) (ScrimController.BUSY_SCRIM_ALPHA * 255));
mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
- mBlurUtils.radiusForRatio(1));
+ mBlurUtils.blurRadiusOfRatio(1));
} else {
background.setAlpha((int) (SHUTDOWN_SCRIM_ALPHA * 255));
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 3933af0..51113ac 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -33,10 +33,10 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
-import android.view.DisplayInfo;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
import android.view.SurfaceControl;
@@ -47,7 +47,9 @@
import com.android.systemui.pip.phone.PipUpdateThread;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
@@ -76,9 +78,9 @@
private final PipBoundsHandler mPipBoundsHandler;
private final PipAnimationController mPipAnimationController;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
- private final Rect mDisplayBounds = new Rect();
private final Rect mLastReportedBounds = new Rect();
private final int mCornerRadius;
+ private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>();
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -201,29 +203,6 @@
}
/**
- * Updates the display dimension with given {@link DisplayInfo}
- */
- @SuppressWarnings("unchecked")
- public void onDisplayInfoChanged(DisplayInfo displayInfo) {
- final Rect newDisplayBounds = new Rect(0, 0,
- displayInfo.logicalWidth, displayInfo.logicalHeight);
- if (!mDisplayBounds.equals(newDisplayBounds)) {
- // Updates the exiting PiP animation in case the screen rotation changes in the middle.
- // It's a legit case that PiP window is in portrait mode on home screen and
- // the application requests landscape once back to fullscreen mode.
- final PipAnimationController.PipTransitionAnimator animator =
- mPipAnimationController.getCurrentAnimator();
- if (animator != null
- && animator.getAnimationType() == ANIM_TYPE_BOUNDS
- && animator.getDestinationBounds().equals(mDisplayBounds)) {
- animator.updateEndValue(newDisplayBounds);
- animator.setDestinationBounds(newDisplayBounds);
- }
- }
- mDisplayBounds.set(newDisplayBounds);
- }
-
- /**
* Callback to issue the final {@link WindowContainerTransaction} on end of movements.
* @param destinationBounds the final bounds.
*/
@@ -252,8 +231,9 @@
} catch (RemoteException e) {
throw new RuntimeException("Unable to get leash", e);
}
+ final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
+ mBoundsToRestore.put(mToken.asBinder(), currentBounds);
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
- final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
scheduleAnimateResizePip(currentBounds, destinationBounds,
TRANSITION_DIRECTION_TO_PIP, DURATION_DEFAULT_MS, null);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
@@ -271,13 +251,15 @@
}
@Override
- public void taskVanished(IWindowContainer token) {
+ public void taskVanished(ActivityManager.RunningTaskInfo info) {
+ IWindowContainer token = info.token;
Objects.requireNonNull(token, "Requires valid IWindowContainer");
if (token.asBinder() != mToken.asBinder()) {
Log.wtf(TAG, "Unrecognized token: " + token);
return;
}
- scheduleAnimateResizePip(mLastReportedBounds, mDisplayBounds,
+ final Rect boundsToRestore = mBoundsToRestore.remove(mToken.asBinder());
+ scheduleAnimateResizePip(mLastReportedBounds, boundsToRestore,
TRANSITION_DIRECTION_TO_FULLSCREEN, DURATION_DEFAULT_MS, null);
mInPip = false;
}
@@ -433,11 +415,16 @@
}
mLastReportedBounds.set(destinationBounds);
try {
+ // If we are animating to fullscreen, then we need to reset the override bounds on the
+ // task to ensure that the task "matches" the parent's bounds
+ Rect taskBounds = direction == TRANSITION_DIRECTION_TO_FULLSCREEN
+ ? null
+ : destinationBounds;
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (direction == TRANSITION_DIRECTION_TO_PIP) {
- wct.scheduleFinishEnterPip(mToken, destinationBounds);
+ wct.scheduleFinishEnterPip(mToken, taskBounds);
} else {
- wct.setBounds(mToken, destinationBounds);
+ wct.setBounds(mToken, taskBounds);
}
wct.setBoundsChangeTransaction(mToken, tx);
mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
index b09d6e1..7dfd99c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
@@ -44,7 +44,7 @@
try {
// Dismiss the PiP once the user disables the app ops setting for that package
final Pair<ComponentName, Integer> topPipActivityInfo =
- PipUtils.getTopPinnedActivity(mContext, mActivityManager);
+ PipUtils.getTopPipActivity(mContext, mActivityManager);
if (topPipActivityInfo.first != null) {
final ApplicationInfo appInfo = mContext.getPackageManager()
.getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 4b97d13..32e9a03 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -115,7 +115,7 @@
@Override
public void onActivityUnpinned() {
- final Pair<ComponentName, Integer> topPipActivityInfo = PipUtils.getTopPinnedActivity(
+ final Pair<ComponentName, Integer> topPipActivityInfo = PipUtils.getTopPipActivity(
mContext, mActivityManager);
final ComponentName topActivity = topPipActivityInfo.first;
mMenuController.onActivityUnpinned();
@@ -128,7 +128,12 @@
}
@Override
- public void onPinnedActivityRestartAttempt(boolean clearedTask) {
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask) {
+ if (task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_PINNED) {
+ return;
+ }
mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */);
}
};
@@ -185,10 +190,7 @@
@Override
public void onDisplayInfoChanged(DisplayInfo displayInfo) {
- mHandler.post(() -> {
- mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
- mPipTaskOrganizer.onDisplayInfoChanged(displayInfo);
- });
+ mHandler.post(() -> mPipBoundsHandler.onDisplayInfoChanged(displayInfo));
}
@Override
@@ -352,7 +354,6 @@
mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
animatingBounds, fromImeAdjustment, fromShelfAdjustment,
mTmpDisplayInfo.rotation);
- mPipTaskOrganizer.onDisplayInfoChanged(mTmpDisplayInfo);
}
public void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
index e57b416..849a62a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -231,7 +231,7 @@
*/
private void resolveActiveMediaController(List<MediaController> controllers) {
if (controllers != null) {
- final ComponentName topActivity = PipUtils.getTopPinnedActivity(mContext,
+ final ComponentName topActivity = PipUtils.getTopPipActivity(mContext,
mActivityManager).first;
if (topActivity != null) {
for (int i = 0; i < controllers.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index fc04f79..2b9b171 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -569,7 +569,7 @@
private void showSettings() {
final Pair<ComponentName, Integer> topPipActivityInfo =
- PipUtils.getTopPinnedActivity(this, ActivityManager.getService());
+ PipUtils.getTopPipActivity(this, ActivityManager.getService());
if (topPipActivityInfo.first != null) {
final UserHandle user = UserHandle.of(topPipActivityInfo.second);
final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 90db91a..b5fb1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -31,6 +31,7 @@
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Pair;
import android.util.Size;
import android.view.IPinnedStackController;
import android.view.InputEvent;
@@ -148,8 +149,11 @@
@Override
public void onPipDismiss() {
- MetricsLoggerWrapper.logPictureInPictureDismissByTap(mContext,
- PipUtils.getTopPinnedActivity(mContext, mActivityManager));
+ Pair<ComponentName, Integer> topPipActivity = PipUtils.getTopPipActivity(mContext,
+ mActivityManager);
+ if (topPipActivity.first != null) {
+ MetricsLoggerWrapper.logPictureInPictureDismissByTap(mContext, topPipActivity);
+ }
mMotionHelper.dismissPip();
}
@@ -653,7 +657,7 @@
// Check if the user dragged or flung the PiP offscreen to dismiss it
if (mMotionHelper.shouldDismissPip() || isFlingToBot) {
MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext,
- PipUtils.getTopPinnedActivity(mContext, mActivityManager));
+ PipUtils.getTopPipActivity(mContext, mActivityManager));
mMotionHelper.animateDismiss(
vel.x, vel.y,
PipTouchHandler.this::updateDismissFraction /* updateAction */);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
index 1ed1904..4cfec01 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
@@ -36,7 +36,7 @@
* @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack.
* The component name may be null if no such activity exists.
*/
- public static Pair<ComponentName, Integer> getTopPinnedActivity(Context context,
+ public static Pair<ComponentName, Integer> getTopPipActivity(Context context,
IActivityManager activityManager) {
try {
final String sysUiPackageName = context.getPackageName();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index a5e9dbc..0c5a4d7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -680,7 +680,12 @@
}
@Override
- public void onPinnedActivityRestartAttempt(boolean clearedTask) {
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) {
+ if (task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_PINNED) {
+ return;
+ }
if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
// If PIPed activity is launched again by Launcher or intent, make it fullscreen.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 17ac5e5..fab7191 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -274,8 +274,8 @@
try {
tile = createTile(tileSpec);
if (tile != null) {
+ tile.setTileSpec(tileSpec);
if (tile.isAvailable()) {
- tile.setTileSpec(tileSpec);
newTiles.put(tileSpec, tile);
mQSLogger.logTileAdded(tileSpec);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index f3e2f10..5bf44c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -20,6 +20,8 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.trust.TrustManager;
@@ -37,6 +39,7 @@
import com.android.systemui.R;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -63,6 +66,21 @@
private TrustManager mTrustManager;
private OverviewProxyService mOverviewProxyService;
+ private TaskStackChangeListener mListener = new TaskStackChangeListener() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask) {
+ if (task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ return;
+ }
+
+ if (homeTaskVisible) {
+ showRecentApps(false /* triggeredFromAltTab */);
+ }
+ }
+ };
+
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy,
@@ -77,6 +95,7 @@
mHandler = new Handler();
mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mListener);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index c6eecf26..ea5ec05 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -129,217 +129,221 @@
}
};
- private DisplayImeController.ImePositionProcessor mImePositionProcessor =
- new DisplayImeController.ImePositionProcessor() {
- /**
- * These are the y positions of the top of the IME surface when it is hidden and
- * when it is shown respectively. These are NOT necessarily the top of the visible
- * IME itself.
- */
- private int mHiddenTop = 0;
- private int mShownTop = 0;
+ private class DividerImeController implements DisplayImeController.ImePositionProcessor {
+ /**
+ * These are the y positions of the top of the IME surface when it is hidden and when it is
+ * shown respectively. These are NOT necessarily the top of the visible IME itself.
+ */
+ private int mHiddenTop = 0;
+ private int mShownTop = 0;
- // The following are target states (what we are curretly animating towards).
- /**
- * {@code true} if, at the end of the animation, the split task positions should be
- * adjusted by height of the IME. This happens when the secondary split is the IME
- * target.
- */
- private boolean mTargetAdjusted = false;
- /**
- * {@code true} if, at the end of the animation, the IME should be shown/visible
- * regardless of what has focus.
- */
- private boolean mTargetShown = false;
+ // The following are target states (what we are curretly animating towards).
+ /**
+ * {@code true} if, at the end of the animation, the split task positions should be
+ * adjusted by height of the IME. This happens when the secondary split is the IME target.
+ */
+ private boolean mTargetAdjusted = false;
+ /**
+ * {@code true} if, at the end of the animation, the IME should be shown/visible
+ * regardless of what has focus.
+ */
+ private boolean mTargetShown = false;
+ private float mTargetPrimaryDim = 0.f;
+ private float mTargetSecondaryDim = 0.f;
- // The following are the current (most recent) states set during animation
- /**
- * {@code true} if the secondary split has IME focus.
- */
- private boolean mSecondaryHasFocus = false;
- /** The dimming currently applied to the primary/secondary splits. */
- private float mLastPrimaryDim = 0.f;
- private float mLastSecondaryDim = 0.f;
- /** The most recent y position of the top of the IME surface */
- private int mLastAdjustTop = -1;
+ // The following are the current (most recent) states set during animation
+ /** {@code true} if the secondary split has IME focus. */
+ private boolean mSecondaryHasFocus = false;
+ /** The dimming currently applied to the primary/secondary splits. */
+ private float mLastPrimaryDim = 0.f;
+ private float mLastSecondaryDim = 0.f;
+ /** The most recent y position of the top of the IME surface */
+ private int mLastAdjustTop = -1;
- // The following are states reached last time an animation fully completed.
- /** {@code true} if the IME was shown/visible by the last-completed animation. */
- private boolean mImeWasShown = false;
- /**
- * {@code true} if the split positions were adjusted by the last-completed
- * animation.
- */
- private boolean mAdjusted = false;
+ // The following are states reached last time an animation fully completed.
+ /** {@code true} if the IME was shown/visible by the last-completed animation. */
+ private boolean mImeWasShown = false;
+ /** {@code true} if the split positions were adjusted by the last-completed animation. */
+ private boolean mAdjusted = false;
- /**
- * When some aspect of split-screen needs to animate independent from the IME,
- * this will be non-null and control split animation.
- */
- @Nullable
- private ValueAnimator mAnimation = null;
+ /**
+ * When some aspect of split-screen needs to animate independent from the IME,
+ * this will be non-null and control split animation.
+ */
+ @Nullable
+ private ValueAnimator mAnimation = null;
- private boolean getSecondaryHasFocus(int displayId) {
- try {
- IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController()
- .getImeTarget(displayId);
- return imeSplit != null
- && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to get IME target", e);
- }
- return false;
- }
+ private boolean getSecondaryHasFocus(int displayId) {
+ try {
+ IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController()
+ .getImeTarget(displayId);
+ return imeSplit != null
+ && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to get IME target", e);
+ }
+ return false;
+ }
+ @Override
+ public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean imeShouldShow, SurfaceControl.Transaction t) {
+ if (!inSplitMode()) {
+ return;
+ }
+ final boolean splitIsVisible = !mView.isHidden();
+ mSecondaryHasFocus = getSecondaryHasFocus(displayId);
+ mTargetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
+ && !mSplitLayout.mDisplayLayout.isLandscape();
+ mHiddenTop = hiddenTop;
+ mShownTop = shownTop;
+ mTargetShown = imeShouldShow;
+ if (mLastAdjustTop < 0) {
+ mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
+ }
+ mTargetPrimaryDim = (mSecondaryHasFocus && mTargetShown && splitIsVisible)
+ ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ mTargetSecondaryDim = (!mSecondaryHasFocus && mTargetShown && splitIsVisible)
+ ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ if (mAnimation != null || (mImeWasShown && imeShouldShow
+ && mTargetAdjusted != mAdjusted)) {
+ // We need to animate adjustment independently of the IME position, so
+ // start our own animation to drive adjustment. This happens when a
+ // different split's editor has gained focus while the IME is still visible.
+ startAsyncAnimation();
+ }
+ if (splitIsVisible) {
+ // If split is hidden, we don't want to trigger any relayouts that would cause the
+ // divider to show again.
+ updateImeAdjustState();
+ }
+ }
+
+ private void updateImeAdjustState() {
+ // Reposition the server's secondary split position so that it evaluates
+ // insets properly.
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (mTargetAdjusted) {
+ mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
+ wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
+ // "Freeze" the configuration size so that the app doesn't get a config
+ // or relaunch. This is required because normally nav-bar contributes
+ // to configuration bounds (via nondecorframe).
+ Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
+ .windowConfiguration.getAppBounds());
+ adjustAppBounds.offset(0, mSplitLayout.mAdjustedSecondary.top
+ - mSplitLayout.mSecondary.top);
+ wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
+ wct.setScreenSizeDp(mSplits.mSecondary.token,
+ mSplits.mSecondary.configuration.screenWidthDp,
+ mSplits.mSecondary.configuration.screenHeightDp);
+ } else {
+ wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
+ wct.setAppBounds(mSplits.mSecondary.token, null);
+ wct.setScreenSizeDp(mSplits.mSecondary.token,
+ SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+ }
+ try {
+ ActivityTaskManager.getTaskOrganizerController()
+ .applyContainerTransaction(wct, null /* organizer */);
+ } catch (RemoteException e) {
+ }
+
+ // Update all the adjusted-for-ime states
+ mView.setAdjustedForIme(mTargetShown, mTargetShown
+ ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
+ : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
+ setAdjustedForIme(mTargetShown);
+ }
+
+ @Override
+ public void onImePositionChanged(int displayId, int imeTop,
+ SurfaceControl.Transaction t) {
+ if (mAnimation != null || !inSplitMode()) {
+ // Not synchronized with IME anymore, so return.
+ return;
+ }
+ final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
+ final float progress = mTargetShown ? fraction : 1.f - fraction;
+ onProgress(progress, t);
+ }
+
+ @Override
+ public void onImeEndPositioning(int displayId, boolean cancelled,
+ SurfaceControl.Transaction t) {
+ if (mAnimation != null || !inSplitMode()) {
+ // Not synchronized with IME anymore, so return.
+ return;
+ }
+ onEnd(cancelled, t);
+ }
+
+ private void onProgress(float progress, SurfaceControl.Transaction t) {
+ if (mTargetAdjusted != mAdjusted) {
+ final float fraction = mTargetAdjusted ? progress : 1.f - progress;
+ mLastAdjustTop = (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
+ mSplitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
+ mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
+ mSplitLayout.mAdjustedSecondary);
+ }
+ final float invProg = 1.f - progress;
+ mView.setResizeDimLayer(t, true /* primary */,
+ mLastPrimaryDim * invProg + progress * mTargetPrimaryDim);
+ mView.setResizeDimLayer(t, false /* primary */,
+ mLastSecondaryDim * invProg + progress * mTargetSecondaryDim);
+ }
+
+ private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
+ if (!cancelled) {
+ onProgress(1.f, t);
+ mAdjusted = mTargetAdjusted;
+ mImeWasShown = mTargetShown;
+ mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
+ mLastPrimaryDim = mTargetPrimaryDim;
+ mLastSecondaryDim = mTargetSecondaryDim;
+ }
+ }
+
+ private void startAsyncAnimation() {
+ if (mAnimation != null) {
+ mAnimation.cancel();
+ }
+ mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
+ mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
+ if (mTargetAdjusted != mAdjusted) {
+ final float fraction =
+ ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
+ final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
+ mAnimation.setCurrentFraction(progress);
+ }
+
+ mAnimation.addUpdateListener(animation -> {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ float value = (float) animation.getAnimatedValue();
+ onProgress(value, t);
+ t.apply();
+ mTransactionPool.release(t);
+ });
+ mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancel = false;
@Override
- public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean imeShouldShow, SurfaceControl.Transaction t) {
- mSecondaryHasFocus = getSecondaryHasFocus(displayId);
- mTargetAdjusted = imeShouldShow && mSecondaryHasFocus
- && !mSplitLayout.mDisplayLayout.isLandscape();
- mHiddenTop = hiddenTop;
- mShownTop = shownTop;
- mTargetShown = imeShouldShow;
- if (mLastAdjustTop < 0) {
- mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
- }
- if (mAnimation != null || (mImeWasShown && imeShouldShow
- && mTargetAdjusted != mAdjusted)) {
- // We need to animate adjustment independently of the IME position, so
- // start our own animation to drive adjustment. This happens when a
- // different split's editor has gained focus while the IME is still visible.
- startAsyncAnimation();
- }
- // Reposition the server's secondary split position so that it evaluates
- // insets properly.
- WindowContainerTransaction wct = new WindowContainerTransaction();
- if (mTargetAdjusted) {
- mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
- wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
- // "Freeze" the configuration size so that the app doesn't get a config
- // or relaunch. This is required because normally nav-bar contributes
- // to configuration bounds (via nondecorframe).
- Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
- .windowConfiguration.getAppBounds());
- adjustAppBounds.offset(0, mSplitLayout.mAdjustedSecondary.top
- - mSplitLayout.mSecondary.top);
- wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
- wct.setScreenSizeDp(mSplits.mSecondary.token,
- mSplits.mSecondary.configuration.screenWidthDp,
- mSplits.mSecondary.configuration.screenHeightDp);
- } else {
- wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
- wct.setAppBounds(mSplits.mSecondary.token, null);
- wct.setScreenSizeDp(mSplits.mSecondary.token,
- SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
- }
- try {
- ActivityTaskManager.getTaskOrganizerController()
- .applyContainerTransaction(wct, null /* organizer */);
- } catch (RemoteException e) {
- }
-
- // Update all the adjusted-for-ime states
- mView.setAdjustedForIme(mTargetShown, mTargetShown
- ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
- : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
- setAdjustedForIme(mTargetShown);
+ public void onAnimationCancel(Animator animation) {
+ mCancel = true;
}
-
@Override
- public void onImePositionChanged(int displayId, int imeTop,
- SurfaceControl.Transaction t) {
- if (mAnimation != null) {
- // Not synchronized with IME anymore, so return.
- return;
- }
- final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
- final float progress = mTargetShown ? fraction : 1.f - fraction;
- onProgress(progress, t);
+ public void onAnimationEnd(Animator animation) {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ onEnd(mCancel, t);
+ t.apply();
+ mTransactionPool.release(t);
+ mAnimation = null;
}
-
- @Override
- public void onImeEndPositioning(int displayId, boolean cancelled,
- SurfaceControl.Transaction t) {
- if (mAnimation != null) {
- // Not synchronized with IME anymore, so return.
- return;
- }
- onEnd(cancelled, t);
- }
-
- private void onProgress(float progress, SurfaceControl.Transaction t) {
- if (mTargetAdjusted != mAdjusted) {
- final float fraction = mTargetAdjusted ? progress : 1.f - progress;
- mLastAdjustTop =
- (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
- mSplitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
- mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
- mSplitLayout.mAdjustedSecondary);
- }
- final float invProg = 1.f - progress;
- final float targetPrimaryDim = (mSecondaryHasFocus && mTargetShown)
- ? ADJUSTED_NONFOCUS_DIM : 0.f;
- final float targetSecondaryDim = (!mSecondaryHasFocus && mTargetShown)
- ? ADJUSTED_NONFOCUS_DIM : 0.f;
- mView.setResizeDimLayer(t, true /* primary */,
- mLastPrimaryDim * invProg + progress * targetPrimaryDim);
- mView.setResizeDimLayer(t, false /* primary */,
- mLastSecondaryDim * invProg + progress * targetSecondaryDim);
- }
-
- private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
- if (!cancelled) {
- onProgress(1.f, t);
- mAdjusted = mTargetAdjusted;
- mImeWasShown = mTargetShown;
- mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
- mLastPrimaryDim =
- (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
- mLastSecondaryDim =
- (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
- }
- }
-
- private void startAsyncAnimation() {
- if (mAnimation != null) {
- mAnimation.cancel();
- }
- mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
- mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
- if (mTargetAdjusted != mAdjusted) {
- final float fraction =
- ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
- final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
- mAnimation.setCurrentFraction(progress);
- }
-
- mAnimation.addUpdateListener(animation -> {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- float value = (float) animation.getAnimatedValue();
- onProgress(value, t);
- t.apply();
- mTransactionPool.release(t);
- });
- mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
- mAnimation.addListener(new AnimatorListenerAdapter() {
- private boolean mCancel = false;
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancel = true;
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- onEnd(mCancel, t);
- t.apply();
- mTransactionPool.release(t);
- mAnimation = null;
- }
- });
- mAnimation.start();
- }
- };
+ });
+ mAnimation.start();
+ }
+ }
+ private final DividerImeController mImePositionProcessor = new DividerImeController();
public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
DisplayController displayController, SystemWindows systemWindows,
@@ -513,44 +517,39 @@
}
}
- private void setHomeStackResizable(boolean resizable) {
- if (mHomeStackResizable == resizable) {
- return;
- }
- mHomeStackResizable = resizable;
- if (!inSplitMode()) {
- return;
- }
- WindowManagerProxy.applyHomeTasksMinimized(mSplitLayout, mSplits.mSecondary.token);
- }
-
- private void updateMinimizedDockedStack(final boolean minimized, final long animDuration,
- final boolean isHomeStackResizable) {
- setHomeStackResizable(isHomeStackResizable);
- if (animDuration > 0) {
- mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable);
- } else {
- mView.setMinimizedDockStack(minimized, isHomeStackResizable);
- }
- updateTouchable();
- }
-
/** Switch to minimized state if appropriate */
public void setMinimized(final boolean minimized) {
mHandler.post(() -> {
- if (!inSplitMode()) {
- return;
- }
- if (mMinimized == minimized) {
- return;
- }
- mMinimized = minimized;
- WindowManagerProxy.applyPrimaryFocusable(mSplits, !mMinimized);
- mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
- updateTouchable();
+ setHomeMinimized(minimized, mHomeStackResizable);
});
}
+ private void setHomeMinimized(final boolean minimized, boolean homeStackResizable) {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ // Update minimized state
+ if (mMinimized != minimized) {
+ mMinimized = minimized;
+ }
+ // Always set this because we could be entering split when mMinimized is already true
+ wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
+
+ // Update home-stack resizability
+ if (mHomeStackResizable != homeStackResizable) {
+ mHomeStackResizable = homeStackResizable;
+ if (inSplitMode()) {
+ WindowManagerProxy.applyHomeTasksMinimized(
+ mSplitLayout, mSplits.mSecondary.token, wct);
+ }
+ }
+
+ // Sync state to DividerView if it exists.
+ if (mView != null) {
+ mView.setMinimizedDockStack(minimized, getAnimDuration(), homeStackResizable);
+ }
+ updateTouchable();
+ WindowManagerProxy.applyContainerTransaction(wct);
+ }
+
void setAdjustedForIme(boolean adjustedForIme) {
if (mAdjustedForIme == adjustedForIme) {
return;
@@ -646,46 +645,24 @@
}
void ensureMinimizedSplit() {
- final boolean wasMinimized = mMinimized;
- mMinimized = true;
- setHomeStackResizable(mSplits.mSecondary.isResizable());
- WindowManagerProxy.applyPrimaryFocusable(mSplits, false /* focusable */);
+ setHomeMinimized(true /* minimized */, mSplits.mSecondary.isResizable());
if (!inSplitMode()) {
// Wasn't in split-mode yet, so enter now.
if (DEBUG) {
Log.d(TAG, " entering split mode with minimized=true");
}
updateVisibility(true /* visible */);
- } else if (!wasMinimized) {
- if (DEBUG) {
- Log.d(TAG, " in split mode, but minimizing ");
- }
- // Was already in split-mode, update just minimized state.
- updateMinimizedDockedStack(mMinimized, getAnimDuration(),
- mHomeStackResizable);
}
}
void ensureNormalSplit() {
- if (mMinimized) {
- WindowManagerProxy.applyPrimaryFocusable(mSplits, true /* focusable */);
- }
+ setHomeMinimized(false /* minimized */, mHomeStackResizable);
if (!inSplitMode()) {
// Wasn't in split-mode, so enter now.
if (DEBUG) {
Log.d(TAG, " enter split mode unminimized ");
}
- mMinimized = false;
updateVisibility(true /* visible */);
}
- if (mMinimized) {
- // Was in minimized state, so leave that.
- if (DEBUG) {
- Log.d(TAG, " in split mode already, but unminimizing ");
- }
- mMinimized = false;
- updateMinimizedDockedStack(mMinimized, getAnimDuration(),
- mHomeStackResizable);
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 477cbb7..4114bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -165,6 +165,10 @@
// The view is removed or in the process of been removed from the system.
private boolean mRemoved;
+ // Whether the surface for this view has been hidden regardless of actual visibility. This is
+ // used interact with keyguard.
+ private boolean mSurfaceHidden = false;
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -414,6 +418,10 @@
/** Unlike setVisible, this directly hides the surface without changing view visibility. */
void setHidden(boolean hidden) {
+ if (mSurfaceHidden == hidden) {
+ return;
+ }
+ mSurfaceHidden = hidden;
post(() -> {
final SurfaceControl sc = getWindowSurfaceControl();
if (sc == null) {
@@ -430,6 +438,10 @@
});
}
+ boolean isHidden() {
+ return mSurfaceHidden;
+ }
+
public boolean startDragging(boolean animate, boolean touching) {
cancelFlingAnimation();
if (touching) {
@@ -1071,7 +1083,7 @@
void setResizeDimLayer(Transaction t, boolean primary, float alpha) {
SurfaceControl dim = primary ? mTiles.mPrimaryDim : mTiles.mSecondaryDim;
- if (alpha <= 0.f) {
+ if (alpha <= 0.001f) {
t.hide(dim);
} else {
t.setAlpha(dim, alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 3020a25..729df38 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -88,6 +88,9 @@
}
public void setTouchable(boolean touchable) {
+ if (mView == null) {
+ return;
+ }
boolean changed = false;
if (!touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) == 0) {
mLp.flags |= FLAG_NOT_TOUCHABLE;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 5cc8799..48ea4ae 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -88,7 +88,7 @@
}
@Override
- public void taskVanished(IWindowContainer container) {
+ public void taskVanished(RunningTaskInfo taskInfo) {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 167c33a..fea57a3 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -21,6 +21,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.graphics.Rect;
@@ -137,17 +138,13 @@
return resizable;
}
- static void applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent) {
- applyHomeTasksMinimized(layout, parent, null /* transaction */);
- }
-
/**
* Assign a fixed override-bounds to home tasks that reflect their geometry while the primary
* split is minimized. This actually "sticks out" of the secondary split area, but when in
* minimized mode, the secondary split gets a 'negative' crop to expose it.
*/
static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent,
- WindowContainerTransaction t) {
+ @NonNull WindowContainerTransaction wct) {
// Resize the home/recents stacks to the larger minimized-state size
final Rect homeBounds;
final ArrayList<IWindowContainer> homeStacks = new ArrayList<>();
@@ -158,19 +155,9 @@
homeBounds = new Rect(0, 0, layout.mDisplayLayout.width(),
layout.mDisplayLayout.height());
}
- WindowContainerTransaction wct = t != null ? t : new WindowContainerTransaction();
for (int i = homeStacks.size() - 1; i >= 0; --i) {
wct.setBounds(homeStacks.get(i), homeBounds);
}
- if (t != null) {
- return isHomeResizable;
- }
- try {
- ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
- null /* organizer */);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to resize home stacks ", e);
- }
return isHomeResizable;
}
@@ -301,10 +288,8 @@
}
}
- static void applyPrimaryFocusable(SplitScreenTaskOrganizer splits, boolean focusable) {
+ static void applyContainerTransaction(WindowContainerTransaction wct) {
try {
- WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setFocusable(splits.mPrimary.token, focusable);
ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
null /* organizer */);
} catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index 34c0860..c523b7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -50,7 +50,7 @@
/**
* Translates a ratio from 0 to 1 to a blur radius in pixels.
*/
- fun radiusForRatio(ratio: Float): Int {
+ fun blurRadiusOfRatio(ratio: Float): Int {
if (ratio == 0f) {
return 0
}
@@ -58,6 +58,17 @@
}
/**
+ * Translates a blur radius in pixels to a ratio between 0 to 1.
+ */
+ fun ratioOfBlurRadius(blur: Int): Float {
+ if (blur == 0) {
+ return 0f
+ }
+ return MathUtils.map(minBlurRadius.toFloat(), maxBlurRadius.toFloat(),
+ 0f /* maxStart */, 1f /* maxStop */, blur.toFloat())
+ }
+
+ /**
* Applies background blurs to a {@link ViewRootImpl}.
*
* @param viewRootImpl The window root.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
similarity index 83%
rename from packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 6e905a3..901ed3f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -19,6 +19,7 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
+import android.app.WallpaperManager
import android.view.Choreographer
import android.view.View
import androidx.dynamicanimation.animation.FloatPropertyCompat
@@ -30,7 +31,6 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK
-import com.android.systemui.statusbar.phone.NotificationShadeWindowController
import com.android.systemui.statusbar.phone.PanelExpansionListener
import com.android.systemui.statusbar.policy.KeyguardStateController
import java.io.FileDescriptor
@@ -43,13 +43,13 @@
* Controller responsible for statusbar window blur.
*/
@Singleton
-class NotificationShadeWindowBlurController @Inject constructor(
+class NotificationShadeDepthController @Inject constructor(
private val statusBarStateController: SysuiStatusBarStateController,
private val blurUtils: BlurUtils,
private val biometricUnlockController: BiometricUnlockController,
private val keyguardStateController: KeyguardStateController,
- private val notificationShadeWindowController: NotificationShadeWindowController,
private val choreographer: Choreographer,
+ private val wallpaperManager: WallpaperManager,
dumpManager: DumpManager
) : PanelExpansionListener, Dumpable {
companion object {
@@ -63,12 +63,12 @@
private var updateScheduled: Boolean = false
private var shadeExpansion = 1.0f
private val shadeSpring = SpringAnimation(this, object :
- FloatPropertyCompat<NotificationShadeWindowBlurController>("shadeBlurRadius") {
- override fun setValue(rect: NotificationShadeWindowBlurController?, value: Float) {
+ FloatPropertyCompat<NotificationShadeDepthController>("shadeBlurRadius") {
+ override fun setValue(rect: NotificationShadeDepthController?, value: Float) {
shadeBlurRadius = value.toInt()
}
- override fun getValue(rect: NotificationShadeWindowBlurController?): Float {
+ override fun getValue(rect: NotificationShadeDepthController?): Float {
return shadeBlurRadius.toFloat()
}
})
@@ -84,12 +84,6 @@
field = value
scheduleUpdate()
}
- private var incomingNotificationBlurRadius = 0
- set(value) {
- if (field == value) return
- field = value
- scheduleUpdate()
- }
/**
* Callback that updates the window blur value and is called only once per frame.
@@ -97,13 +91,9 @@
private val updateBlurCallback = Choreographer.FrameCallback {
updateScheduled = false
- var notificationBlur = 0
- if (statusBarStateController.state == StatusBarState.KEYGUARD) {
- notificationBlur = (incomingNotificationBlurRadius * shadeExpansion).toInt()
- }
-
- val blur = max(max(shadeBlurRadius, wakeAndUnlockBlurRadius), notificationBlur)
+ val blur = max(shadeBlurRadius, wakeAndUnlockBlurRadius)
blurUtils.applyBlur(root.viewRootImpl, blur)
+ wallpaperManager.setWallpaperZoomOut(root.windowToken, blurUtils.ratioOfBlurRadius(blur))
}
/**
@@ -123,7 +113,7 @@
interpolator = Interpolators.DECELERATE_QUINT
addUpdateListener { animation: ValueAnimator ->
wakeAndUnlockBlurRadius =
- blurUtils.radiusForRatio(animation.animatedValue as Float)
+ blurUtils.blurRadiusOfRatio(animation.animatedValue as Float)
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
@@ -163,7 +153,7 @@
var newBlur = 0
if (statusBarStateController.state == StatusBarState.SHADE) {
- newBlur = blurUtils.radiusForRatio(expansion)
+ newBlur = blurUtils.blurRadiusOfRatio(expansion)
}
if (shadeBlurRadius == newBlur) {
@@ -181,11 +171,11 @@
}
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
- IndentingPrintWriter(pw, " ").use {
+ IndentingPrintWriter(pw, " ").let {
it.println("StatusBarWindowBlurController:")
it.increaseIndent()
it.println("shadeBlurRadius: $shadeBlurRadius")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 8a23e37..2747696 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification
import android.animation.ObjectAnimator
-import android.content.Context
import android.util.FloatProperty
import com.android.systemui.Interpolators
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -26,10 +25,10 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.PanelExpansionListener
+import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import javax.inject.Inject
@@ -37,15 +36,14 @@
@Singleton
class NotificationWakeUpCoordinator @Inject constructor(
- private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
- private val statusBarStateController: StatusBarStateController,
- private val bypassController: KeyguardBypassController,
- private val dozeParameters: DozeParameters)
- : OnHeadsUpChangedListener, StatusBarStateController.StateListener,
- PanelExpansionListener {
+ private val mHeadsUpManager: HeadsUpManager,
+ private val statusBarStateController: StatusBarStateController,
+ private val bypassController: KeyguardBypassController,
+ private val dozeParameters: DozeParameters
+) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, PanelExpansionListener {
- private val mNotificationVisibility
- = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
+ private val mNotificationVisibility = object : FloatProperty<NotificationWakeUpCoordinator>(
+ "notificationVisibility") {
override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) {
coordinator.setVisibilityAmount(value)
@@ -78,10 +76,10 @@
field = value
willWakeUp = false
if (value) {
- if (mNotificationsVisible && !mNotificationsVisibleForExpansion
- && !bypassController.bypassEnabled) {
+ if (mNotificationsVisible && !mNotificationsVisibleForExpansion &&
+ !bypassController.bypassEnabled) {
// We're waking up while pulsing, let's make sure the animation looks nice
- mStackScroller.wakeUpFromPulse();
+ mStackScroller.wakeUpFromPulse()
}
if (bypassController.bypassEnabled && !mNotificationsVisible) {
// Let's make sure our huns become visible once we are waking up in case
@@ -100,7 +98,7 @@
}
private var collapsedEnoughToHide: Boolean = false
- lateinit var iconAreaController : NotificationIconAreaController
+ lateinit var iconAreaController: NotificationIconAreaController
var pulsing: Boolean = false
set(value) {
@@ -132,8 +130,8 @@
var canShow = pulsing
if (bypassController.bypassEnabled) {
// We also allow pulsing on the lock screen!
- canShow = canShow || (wakingUp || willWakeUp || fullyAwake)
- && statusBarStateController.state == StatusBarState.KEYGUARD
+ canShow = canShow || (wakingUp || willWakeUp || fullyAwake) &&
+ statusBarStateController.state == StatusBarState.KEYGUARD
// We want to hide the notifications when collapsed too much
if (collapsedEnoughToHide) {
canShow = false
@@ -143,7 +141,7 @@
}
init {
- mHeadsUpManagerPhone.addListener(this)
+ mHeadsUpManager.addListener(this)
statusBarStateController.addCallback(this)
addListener(object : WakeUpListener {
override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
@@ -155,7 +153,7 @@
increaseSpeed = false)
}
}
- });
+ })
}
fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
@@ -178,46 +176,55 @@
* @param animate should this change be animated
* @param increaseSpeed should the speed be increased of the animation
*/
- fun setNotificationsVisibleForExpansion(visible: Boolean, animate: Boolean,
- increaseSpeed: Boolean) {
+ fun setNotificationsVisibleForExpansion(
+ visible: Boolean,
+ animate: Boolean,
+ increaseSpeed: Boolean
+ ) {
mNotificationsVisibleForExpansion = visible
updateNotificationVisibility(animate, increaseSpeed)
if (!visible && mNotificationsVisible) {
// If we stopped expanding and we're still visible because we had a pulse that hasn't
// times out, let's release them all to make sure were not stuck in a state where
// notifications are visible
- mHeadsUpManagerPhone.releaseAllImmediately()
+ mHeadsUpManager.releaseAllImmediately()
}
}
fun addListener(listener: WakeUpListener) {
- wakeUpListeners.add(listener);
+ wakeUpListeners.add(listener)
}
fun removeListener(listener: WakeUpListener) {
- wakeUpListeners.remove(listener);
+ wakeUpListeners.remove(listener)
}
- private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) {
+ private fun updateNotificationVisibility(
+ animate: Boolean,
+ increaseSpeed: Boolean
+ ) {
// TODO: handle Lockscreen wakeup for bypass when we're not pulsing anymore
- var visible = mNotificationsVisibleForExpansion || mHeadsUpManagerPhone.hasNotifications()
+ var visible = mNotificationsVisibleForExpansion || mHeadsUpManager.hasNotifications()
visible = visible && canShowPulsingHuns
if (!visible && mNotificationsVisible && (wakingUp || willWakeUp) && mDozeAmount != 0.0f) {
// let's not make notifications invisible while waking up, otherwise the animation
// is strange
- return;
+ return
}
setNotificationsVisible(visible, animate, increaseSpeed)
}
- private fun setNotificationsVisible(visible: Boolean, animate: Boolean,
- increaseSpeed: Boolean) {
+ private fun setNotificationsVisible(
+ visible: Boolean,
+ animate: Boolean,
+ increaseSpeed: Boolean
+ ) {
if (mNotificationsVisible == visible) {
return
}
mNotificationsVisible = visible
- mVisibilityAnimator?.cancel();
+ mVisibilityAnimator?.cancel()
if (animate) {
notifyAnimationStart(visible)
startVisibilityAnimation(increaseSpeed)
@@ -230,8 +237,8 @@
if (updateDozeAmountIfBypass()) {
return
}
- if (linear != 1.0f && linear != 0.0f
- && (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
+ if (linear != 1.0f && linear != 0.0f &&
+ (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
// Let's notify the scroller that an animation started
notifyAnimationStart(mLinearDozeAmount == 1.0f)
}
@@ -245,17 +252,17 @@
mStackScroller.setDozeAmount(mDozeAmount)
updateHideAmount()
if (changed && linear == 0.0f) {
- setNotificationsVisible(visible = false, animate = false, increaseSpeed = false);
+ setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
setNotificationsVisibleForExpansion(visible = false, animate = false,
increaseSpeed = false)
}
}
override fun onStateChanged(newState: Int) {
- updateDozeAmountIfBypass();
+ updateDozeAmountIfBypass()
if (bypassController.bypassEnabled &&
- newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED
- && (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
+ newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED &&
+ (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
// We're leaving shade locked. Let's animate the notifications away
setNotificationsVisible(visible = true, increaseSpeed = false, animate = false)
setNotificationsVisible(visible = false, increaseSpeed = false, animate = true)
@@ -266,23 +273,23 @@
override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
val collapsedEnough = expansion <= 0.9f
if (collapsedEnough != this.collapsedEnoughToHide) {
- val couldShowPulsingHuns = canShowPulsingHuns;
+ val couldShowPulsingHuns = canShowPulsingHuns
this.collapsedEnoughToHide = collapsedEnough
if (couldShowPulsingHuns && !canShowPulsingHuns) {
updateNotificationVisibility(animate = true, increaseSpeed = true)
- mHeadsUpManagerPhone.releaseAllImmediately()
+ mHeadsUpManager.releaseAllImmediately()
}
}
}
private fun updateDozeAmountIfBypass(): Boolean {
if (bypassController.bypassEnabled) {
- var amount = 1.0f;
- if (statusBarStateController.state == StatusBarState.SHADE
- || statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
- amount = 0.0f;
+ var amount = 1.0f
+ if (statusBarStateController.state == StatusBarState.SHADE ||
+ statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
+ amount = 0.0f
}
- setDozeAmount(amount, amount)
+ setDozeAmount(amount, amount)
return true
}
return false
@@ -300,7 +307,7 @@
visibilityAnimator.setInterpolator(Interpolators.LINEAR)
var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
if (increaseSpeed) {
- duration = (duration.toFloat() / 1.5F).toLong();
+ duration = (duration.toFloat() / 1.5F).toLong()
}
visibilityAnimator.setDuration(duration)
visibilityAnimator.start()
@@ -311,7 +318,7 @@
mLinearVisibilityAmount = visibilityAmount
mVisibilityAmount = mVisibilityInterpolator.getInterpolation(
visibilityAmount)
- handleAnimationFinished();
+ handleAnimationFinished()
updateHideAmount()
}
@@ -322,7 +329,7 @@
}
}
- fun getWakeUpHeight() : Float {
+ fun getWakeUpHeight(): Float {
return mStackScroller.wakeUpHeight
}
@@ -330,7 +337,7 @@
val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount)
mStackScroller.setHideAmount(linearAmount, amount)
- notificationsFullyHidden = linearAmount == 1.0f;
+ notificationsFullyHidden = linearAmount == 1.0f
}
private fun notifyAnimationStart(awake: Boolean) {
@@ -361,7 +368,7 @@
// if we animate, we see the shelf briefly visible. Instead we fully animate
// the notification and its background out
animate = false
- } else if (!wakingUp && !willWakeUp){
+ } else if (!wakingUp && !willWakeUp) {
// TODO: look that this is done properly and not by anyone else
entry.setHeadsUpAnimatingAway(true)
mEntrySetToClearWhenFinished.add(entry)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index e8a62e4..4beeede 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -37,8 +37,8 @@
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NotificationClicker;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
@@ -66,7 +66,7 @@
private static final String TAG = "NotificationViewManager";
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final Context mContext;
private final NotifBindPipeline mNotifBindPipeline;
@@ -97,7 +97,7 @@
StatusBarStateController statusBarStateController,
NotificationGroupManager notificationGroupManager,
NotificationGutsManager notificationGutsManager,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptionStateProvider,
Provider<RowInflaterTask> rowInflaterTaskProvider,
ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder) {
mContext = context;
@@ -106,7 +106,7 @@
mMessagingUtil = notificationMessagingUtil;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mNotificationLockscreenUserManager = notificationLockscreenUserManager;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
mRowInflaterTaskProvider = rowInflaterTaskProvider;
mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
}
@@ -243,7 +243,7 @@
params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
params.setUseLowPriority(entry.isAmbient());
- if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
+ if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) {
params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP);
}
//TODO: Replace this API with RowContentBindParams directly
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 3c0ac7e..1d8e979 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -31,10 +31,8 @@
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
@@ -44,7 +42,12 @@
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -56,6 +59,7 @@
import javax.inject.Singleton;
+import dagger.Binds;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -125,7 +129,7 @@
NotificationRemoteInputManager remoteInputManager,
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationListener notificationListener,
HeadsUpManager headsUpManager) {
return new NotificationAlertingManager(
@@ -133,7 +137,7 @@
remoteInputManager,
visualStabilityManager,
statusBarStateController,
- notificationInterruptionStateProvider,
+ notificationInterruptStateProvider,
notificationListener,
headsUpManager);
}
@@ -146,13 +150,22 @@
@UiBackground Executor uiBgExecutor,
NotificationEntryManager entryManager,
StatusBarStateController statusBarStateController,
- NotificationLogger.ExpansionStateLogger expansionStateLogger) {
+ NotificationLogger.ExpansionStateLogger expansionStateLogger,
+ NotificationPanelLogger notificationPanelLogger) {
return new NotificationLogger(
notificationListener,
uiBgExecutor,
entryManager,
statusBarStateController,
- expansionStateLogger);
+ expansionStateLogger,
+ notificationPanelLogger);
+ }
+
+ /** Provides an instance of {@link NotificationPanelLogger} */
+ @Singleton
+ @Provides
+ static NotificationPanelLogger provideNotificationPanelLogger() {
+ return new NotificationPanelLoggerImpl();
}
/** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */
@@ -199,4 +212,9 @@
NotificationEntryManager entryManager) {
return featureFlags.isNewNotifPipelineRenderingEnabled() ? pipeline.get() : entryManager;
}
+
+ /** */
+ @Binds
+ NotificationInterruptStateProvider bindNotificationInterruptStateProvider(
+ NotificationInterruptStateProviderImpl notificationInterruptStateProviderImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
index 269a7a5..88888d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.statusbar.notification
+package com.android.systemui.statusbar.notification.interruption
import android.content.Context
import android.media.MediaMetadata
@@ -24,6 +24,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
index df21f0b..b572502 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification;
+package com.android.systemui.statusbar.notification.interruption;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
@@ -27,6 +27,9 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -39,7 +42,7 @@
private final NotificationRemoteInputManager mRemoteInputManager;
private final VisualStabilityManager mVisualStabilityManager;
private final StatusBarStateController mStatusBarStateController;
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final NotificationListener mNotificationListener;
private HeadsUpManager mHeadsUpManager;
@@ -52,13 +55,13 @@
NotificationRemoteInputManager remoteInputManager,
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptionStateProvider,
NotificationListener notificationListener,
HeadsUpManager headsUpManager) {
mRemoteInputManager = remoteInputManager;
mVisualStabilityManager = visualStabilityManager;
mStatusBarStateController = statusBarStateController;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
mNotificationListener = notificationListener;
mHeadsUpManager = headsUpManager;
@@ -94,7 +97,7 @@
if (entry.getRow().getPrivateLayout().getHeadsUpChild() != null) {
// Possible for shouldHeadsUp to change between the inflation starting and ending.
// If it does and we no longer need to heads up, we should free the view.
- if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
+ if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) {
mHeadsUpManager.showNotification(entry);
if (!mStatusBarStateController.isDozing()) {
// Mark as seen immediately
@@ -109,7 +112,7 @@
private void updateAlertState(NotificationEntry entry) {
boolean alertAgain = alertAgain(entry, entry.getSbn().getNotification());
// includes check for whether this notification should be filtered:
- boolean shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
+ boolean shouldAlert = mNotificationInterruptStateProvider.shouldHeadsUp(entry);
final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.getKey());
if (wasAlerting) {
if (shouldAlert) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
new file mode 100644
index 0000000..3292a8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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.systemui.statusbar.notification.interruption;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/**
+ * Provides bubble-up and heads-up state for notification entries.
+ *
+ * When a notification is heads-up when dozing, this is also called "pulsing."
+ */
+public interface NotificationInterruptStateProvider {
+ /**
+ * If the device is awake (not dozing):
+ * Whether the notification should peek in from the top and alert the user.
+ *
+ * If the device is dozing:
+ * Whether the notification should show the ambient view of the notification ("pulse").
+ *
+ * @param entry the entry to check
+ * @return true if the entry should heads up, false otherwise
+ */
+ boolean shouldHeadsUp(NotificationEntry entry);
+
+ /**
+ * Whether the notification should appear as a bubble with a fly-out on top of the screen.
+ *
+ * @param entry the entry to check
+ * @return true if the entry should bubble up, false otherwise
+ */
+ boolean shouldBubbleUp(NotificationEntry entry);
+
+ /**
+ * Whether to launch the entry's full screen intent when the entry is added.
+ *
+ * @param entry the entry that was added
+ * @return {@code true} if we should launch the full screen intent
+ */
+ boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry);
+
+ /**
+ * Add a component that can suppress visual interruptions.
+ */
+ void addSuppressor(NotificationInterruptSuppressor suppressor);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index bbf2dde..46d5044 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -14,33 +14,35 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification;
+package com.android.systemui.statusbar.notification.interruption;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import android.app.NotificationManager;
-import android.content.Context;
+import android.content.ContentResolver;
import android.database.ContentObserver;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
-import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -48,120 +50,84 @@
* Provides heads-up and pulsing state for notification entries.
*/
@Singleton
-public class NotificationInterruptionStateProvider {
-
+public class NotificationInterruptStateProviderImpl implements NotificationInterruptStateProvider {
private static final String TAG = "InterruptionStateProvider";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true; //false;
private static final boolean DEBUG_HEADS_UP = true;
private static final boolean ENABLE_HEADS_UP = true;
private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
+ private final List<NotificationInterruptSuppressor> mSuppressors = new ArrayList<>();
private final StatusBarStateController mStatusBarStateController;
private final NotificationFilter mNotificationFilter;
- private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
-
- private final Context mContext;
+ private final ContentResolver mContentResolver;
private final PowerManager mPowerManager;
private final IDreamManager mDreamManager;
+ private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private final BatteryController mBatteryController;
-
- private NotificationPresenter mPresenter;
+ private final ContentObserver mHeadsUpObserver;
private HeadsUpManager mHeadsUpManager;
- private HeadsUpSuppressor mHeadsUpSuppressor;
- private ContentObserver mHeadsUpObserver;
@VisibleForTesting
protected boolean mUseHeadsUp = false;
- private boolean mDisableNotificationAlerts;
@Inject
- public NotificationInterruptionStateProvider(Context context, NotificationFilter filter,
- StatusBarStateController stateController, BatteryController batteryController) {
- this(context,
- (PowerManager) context.getSystemService(Context.POWER_SERVICE),
- IDreamManager.Stub.asInterface(
- ServiceManager.checkService(DreamService.DREAM_SERVICE)),
- new AmbientDisplayConfiguration(context),
- filter,
- batteryController,
- stateController);
- }
-
- @VisibleForTesting
- protected NotificationInterruptionStateProvider(
- Context context,
+ public NotificationInterruptStateProviderImpl(
+ ContentResolver contentResolver,
PowerManager powerManager,
IDreamManager dreamManager,
AmbientDisplayConfiguration ambientDisplayConfiguration,
NotificationFilter notificationFilter,
BatteryController batteryController,
- StatusBarStateController statusBarStateController) {
- mContext = context;
+ StatusBarStateController statusBarStateController,
+ HeadsUpManager headsUpManager,
+ @Main Handler mainHandler) {
+ mContentResolver = contentResolver;
mPowerManager = powerManager;
mDreamManager = dreamManager;
mBatteryController = batteryController;
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
mNotificationFilter = notificationFilter;
mStatusBarStateController = statusBarStateController;
- }
-
- /** Sets up late-binding dependencies for this component. */
- public void setUpWithPresenter(
- NotificationPresenter notificationPresenter,
- HeadsUpManager headsUpManager,
- HeadsUpSuppressor headsUpSuppressor) {
- setUpWithPresenter(notificationPresenter, headsUpManager, headsUpSuppressor,
- new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
- @Override
- public void onChange(boolean selfChange) {
- boolean wasUsing = mUseHeadsUp;
- mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts
- && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
- Settings.Global.HEADS_UP_OFF);
- Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
- if (wasUsing != mUseHeadsUp) {
- if (!mUseHeadsUp) {
- Log.d(TAG,
- "dismissing any existing heads up notification on disable"
- + " event");
- mHeadsUpManager.releaseAllImmediately();
- }
- }
- }
- });
- }
-
- /** Sets up late-binding dependencies for this component. */
- public void setUpWithPresenter(
- NotificationPresenter notificationPresenter,
- HeadsUpManager headsUpManager,
- HeadsUpSuppressor headsUpSuppressor,
- ContentObserver observer) {
- mPresenter = notificationPresenter;
mHeadsUpManager = headsUpManager;
- mHeadsUpSuppressor = headsUpSuppressor;
- mHeadsUpObserver = observer;
+ mHeadsUpObserver = new ContentObserver(mainHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ boolean wasUsing = mUseHeadsUp;
+ mUseHeadsUp = ENABLE_HEADS_UP
+ && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
+ mContentResolver,
+ Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+ Settings.Global.HEADS_UP_OFF);
+ Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
+ if (wasUsing != mUseHeadsUp) {
+ if (!mUseHeadsUp) {
+ Log.d(TAG, "dismissing any existing heads up notification on "
+ + "disable event");
+ mHeadsUpManager.releaseAllImmediately();
+ }
+ }
+ }
+ };
if (ENABLE_HEADS_UP) {
- mContext.getContentResolver().registerContentObserver(
+ mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED),
true,
mHeadsUpObserver);
- mContext.getContentResolver().registerContentObserver(
+ mContentResolver.registerContentObserver(
Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
mHeadsUpObserver);
}
mHeadsUpObserver.onChange(true); // set up
}
- /**
- * Whether the notification should appear as a bubble with a fly-out on top of the screen.
- *
- * @param entry the entry to check
- * @return true if the entry should bubble up, false otherwise
- */
+ @Override
+ public void addSuppressor(NotificationInterruptSuppressor suppressor) {
+ mSuppressors.add(suppressor);
+ }
+
+ @Override
public boolean shouldBubbleUp(NotificationEntry entry) {
final StatusBarNotification sbn = entry.getSbn();
@@ -201,12 +167,8 @@
return true;
}
- /**
- * Whether the notification should peek in from the top and alert the user.
- *
- * @param entry the entry to check
- * @return true if the entry should heads up, false otherwise
- */
+
+ @Override
public boolean shouldHeadsUp(NotificationEntry entry) {
if (mStatusBarStateController.isDozing()) {
return shouldHeadsUpWhenDozing(entry);
@@ -215,6 +177,17 @@
}
}
+ /**
+ * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
+ * incoming calls.
+ */
+ @Override
+ public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
+ return entry.getSbn().getNotification().fullScreenIntent != null
+ && (!shouldHeadsUp(entry)
+ || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
+ }
+
private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
@@ -271,13 +244,15 @@
return false;
}
- if (!mHeadsUpSuppressor.canHeadsUp(entry, sbn)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No heads up: aborted by suppressor: " + sbn.getKey());
+ for (int i = 0; i < mSuppressors.size(); i++) {
+ if (mSuppressors.get(i).suppressAwakeHeadsUp(entry)) {
+ if (DEBUG_HEADS_UP) {
+ Log.d(TAG, "No heads up: aborted by suppressor: "
+ + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
+ }
+ return false;
}
- return false;
}
-
return true;
}
@@ -325,7 +300,7 @@
}
return false;
}
- return true;
+ return true;
}
/**
@@ -334,8 +309,7 @@
* @param entry the entry to check
* @return true if these checks pass, false if the notification should not alert
*/
- @VisibleForTesting
- public boolean canAlertCommon(NotificationEntry entry) {
+ private boolean canAlertCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
if (mNotificationFilter.shouldFilterOut(entry)) {
@@ -352,6 +326,16 @@
}
return false;
}
+
+ for (int i = 0; i < mSuppressors.size(); i++) {
+ if (mSuppressors.get(i).suppressInterruptions(entry)) {
+ if (DEBUG_HEADS_UP) {
+ Log.d(TAG, "No alerting: aborted by suppressor: "
+ + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
+ }
+ return false;
+ }
+ }
return true;
}
@@ -361,15 +345,17 @@
* @param entry the entry to check
* @return true if these checks pass, false if the notification should not alert
*/
- @VisibleForTesting
- public boolean canAlertAwakeCommon(NotificationEntry entry) {
+ private boolean canAlertAwakeCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
- if (mPresenter.isDeviceInVrMode()) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: no huns or vr mode");
+ for (int i = 0; i < mSuppressors.size(); i++) {
+ if (mSuppressors.get(i).suppressAwakeInterruptions(entry)) {
+ if (DEBUG_HEADS_UP) {
+ Log.d(TAG, "No alerting: aborted by suppressor: "
+ + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
+ }
+ return false;
}
- return false;
}
if (isSnoozedPackage(sbn)) {
@@ -392,54 +378,4 @@
private boolean isSnoozedPackage(StatusBarNotification sbn) {
return mHeadsUpManager.isSnoozed(sbn.getPackageName());
}
-
- /** Sets whether to disable all alerts. */
- public void setDisableNotificationAlerts(boolean disableNotificationAlerts) {
- mDisableNotificationAlerts = disableNotificationAlerts;
- mHeadsUpObserver.onChange(true);
- }
-
- /** Whether all alerts are disabled. */
- @VisibleForTesting
- public boolean areNotificationAlertsDisabled() {
- return mDisableNotificationAlerts;
- }
-
- /** Whether HUNs should be used. */
- @VisibleForTesting
- public boolean getUseHeadsUp() {
- return mUseHeadsUp;
- }
-
- protected NotificationPresenter getPresenter() {
- return mPresenter;
- }
-
- /**
- * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
- * incoming calls.
- *
- * @param entry the entry that was added
- * @return {@code true} if we should launch the full screen intent
- */
- public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
- return entry.getSbn().getNotification().fullScreenIntent != null
- && (!shouldHeadsUp(entry)
- || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
- }
-
- /** A component which can suppress heads-up notifications due to the overall state of the UI. */
- public interface HeadsUpSuppressor {
- /**
- * Returns false if the provided notification is ineligible for heads-up according to this
- * component.
- *
- * @param entry entry of the notification that might be heads upped
- * @param sbn notification that might be heads upped
- * @return false if the notification can not be heads upped
- */
- boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn);
-
- }
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java
new file mode 100644
index 0000000..c19f8bd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java
@@ -0,0 +1,64 @@
+/*
+ * 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.systemui.statusbar.notification.interruption;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/** A component which can suppress visual interruptions of notifications such as heads-up and
+ * bubble-up.
+ */
+public interface NotificationInterruptSuppressor {
+ /**
+ * A unique name to identify this suppressor.
+ */
+ default String getName() {
+ return this.getClass().getName();
+ }
+
+ /**
+ * Returns true if the provided notification is, when the device is awake, ineligible for
+ * heads-up according to this component.
+ *
+ * @param entry entry of the notification that might heads-up
+ * @return true if the heads up interruption should be suppressed when the device is awake
+ */
+ default boolean suppressAwakeHeadsUp(NotificationEntry entry) {
+ return false;
+ }
+
+ /**
+ * Returns true if the provided notification is, when the device is awake, ineligible for
+ * heads-up or bubble-up according to this component.
+ *
+ * @param entry entry of the notification that might heads-up or bubble-up
+ * @return true if interruptions should be suppressed when the device is awake
+ */
+ default boolean suppressAwakeInterruptions(NotificationEntry entry) {
+ return false;
+ }
+
+ /**
+ * Returns true if the provided notification is, regardless of awake/dozing state,
+ * ineligible for heads-up or bubble-up according to this component.
+ *
+ * @param entry entry of the notification that might heads-up or bubble-up
+ * @return true if interruptions should be suppressed
+ */
+ default boolean suppressInterruptions(NotificationEntry entry) {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 6e161c9..ad04788 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -70,6 +70,7 @@
private final NotificationListenerService mNotificationListener;
private final Executor mUiBgExecutor;
private final NotificationEntryManager mEntryManager;
+ private final NotificationPanelLogger mNotificationPanelLogger;
private HeadsUpManager mHeadsUpManager;
private final ExpansionStateLogger mExpansionStateLogger;
@@ -198,13 +199,15 @@
@UiBackground Executor uiBgExecutor,
NotificationEntryManager entryManager,
StatusBarStateController statusBarStateController,
- ExpansionStateLogger expansionStateLogger) {
+ ExpansionStateLogger expansionStateLogger,
+ NotificationPanelLogger notificationPanelLogger) {
mNotificationListener = notificationListener;
mUiBgExecutor = uiBgExecutor;
mEntryManager = entryManager;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mExpansionStateLogger = expansionStateLogger;
+ mNotificationPanelLogger = notificationPanelLogger;
// Not expected to be destroyed, don't need to unsubscribe
statusBarStateController.addCallback(this);
@@ -264,6 +267,8 @@
// (Note that in cases where the scroller does emit events, this
// additional event doesn't break anything.)
mNotificationLocationsChangedListener.onChildLocationsChanged();
+ mNotificationPanelLogger.logPanelShown(mListContainer.hasPulsingNotifications(),
+ mEntryManager.getVisibleNotifications());
}
private void setDozing(boolean dozing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
new file mode 100644
index 0000000..9a25c48
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -0,0 +1,95 @@
+/*
+ * 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.systemui.statusbar.notification.logging;
+
+import android.annotation.Nullable;
+import android.service.notification.StatusBarNotification;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import java.util.List;
+/**
+ * Statsd logging for notification panel.
+ */
+public interface NotificationPanelLogger {
+
+ /**
+ * Log a NOTIFICATION_PANEL_REPORTED statsd event.
+ * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
+ */
+ void logPanelShown(boolean isLockscreen,
+ @Nullable List<NotificationEntry> visibleNotifications);
+
+ enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Notification panel shown from status bar.")
+ NOTIFICATION_PANEL_OPEN_STATUS_BAR(200),
+ @UiEvent(doc = "Notification panel shown from lockscreen.")
+ NOTIFICATION_PANEL_OPEN_LOCKSCREEN(201);
+
+ private final int mId;
+ NotificationPanelEvent(int id) {
+ mId = id;
+ }
+ @Override public int getId() {
+ return mId;
+ }
+
+ public static NotificationPanelEvent fromLockscreen(boolean isLockscreen) {
+ return isLockscreen ? NOTIFICATION_PANEL_OPEN_LOCKSCREEN :
+ NOTIFICATION_PANEL_OPEN_STATUS_BAR;
+ }
+ }
+
+ /**
+ * Composes a NotificationsList proto from the list of visible notifications.
+ * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
+ * @return NotificationList proto suitable for SysUiStatsLog.write(NOTIFICATION_PANEL_REPORTED)
+ */
+ static Notifications.NotificationList toNotificationProto(
+ @Nullable List<NotificationEntry> visibleNotifications) {
+ Notifications.NotificationList notificationList = new Notifications.NotificationList();
+ if (visibleNotifications == null) {
+ return notificationList;
+ }
+ final Notifications.Notification[] proto_array =
+ new Notifications.Notification[visibleNotifications.size()];
+ int i = 0;
+ for (NotificationEntry ne : visibleNotifications) {
+ final StatusBarNotification n = ne.getSbn();
+ if (n != null) {
+ final Notifications.Notification proto = new Notifications.Notification();
+ proto.uid = n.getUid();
+ proto.packageName = n.getPackageName();
+ if (n.getInstanceId() != null) {
+ proto.instanceId = n.getInstanceId().getId();
+ }
+ // TODO set np.groupInstanceId
+ if (n.getNotification() != null) {
+ proto.isGroupSummary = n.getNotification().isGroupSummary();
+ }
+ proto.section = 1 + ne.getBucket(); // We want 0 to mean not set / unknown
+ proto_array[i] = proto;
+ }
+ ++i;
+ }
+ notificationList.notifications = proto_array;
+ return notificationList;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
new file mode 100644
index 0000000..75a6019
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.systemui.statusbar.notification.logging;
+
+import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import com.google.protobuf.nano.MessageNano;
+
+import java.util.List;
+
+/**
+ * Normal implementation of NotificationPanelLogger.
+ */
+public class NotificationPanelLoggerImpl implements NotificationPanelLogger {
+ @Override
+ public void logPanelShown(boolean isLockscreen,
+ List<NotificationEntry> visibleNotifications) {
+ final Notifications.NotificationList proto = NotificationPanelLogger.toNotificationProto(
+ visibleNotifications);
+ SysUiStatsLog.write(SysUiStatsLog.NOTIFICATION_PANEL_REPORTED,
+ /* int event_id */ NotificationPanelEvent.fromLockscreen(isLockscreen).getId(),
+ /* int num_notifications*/ proto.notifications.length,
+ /* byte[] notifications*/ MessageNano.toByteArray(proto));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
new file mode 100644
index 0000000..552a5fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
@@ -0,0 +1,49 @@
+/*
+ * 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.systemui.statusbar.notification.logging;
+
+/**
+ * NotificationList proto from atoms.proto, duplicated here so that it's accessible in the build.
+ * Must be kept in sync with the version in atoms.proto.
+ */
+
+message Notification {
+ // The notifying app's uid and package.
+ optional int32 uid = 1;
+ optional string package_name = 2;
+ // A small system-assigned identifier for the notification.
+ optional int32 instance_id = 3;
+
+ // Grouping information.
+ optional int32 group_instance_id = 4;
+ optional bool is_group_summary = 5;
+
+ // The section of the shade that the notification is in.
+ // See NotificationSectionsManager.PriorityBucket.
+ enum NotificationSection {
+ SECTION_UNKNOWN = 0;
+ SECTION_HEADS_UP = 1;
+ SECTION_PEOPLE = 2;
+ SECTION_ALERTING = 3;
+ SECTION_SILENT = 4;
+ }
+ optional NotificationSection section = 6;
+}
+
+message NotificationList {
+ repeated Notification notifications = 1; // An ordered sequence of notifications.
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index 597bdb9..be3873a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -83,7 +83,7 @@
private val Ranking.personTypeInfo
get() = when {
- channel.isImportantConversation -> TYPE_IMPORTANT_PERSON
+ channel?.isImportantConversation == true -> TYPE_IMPORTANT_PERSON
isConversation -> TYPE_PERSON
else -> TYPE_NON_PERSON
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index c5c3fff..c54fa29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -27,6 +27,8 @@
*/
public class KeyguardIndicationTextView extends TextView {
+ private CharSequence mText = "";
+
public KeyguardIndicationTextView(Context context) {
super(context);
}
@@ -53,10 +55,12 @@
// TODO: Animation, make sure that we will show one indication long enough.
if (TextUtils.isEmpty(text)) {
+ mText = "";
setVisibility(View.INVISIBLE);
- } else {
+ } else if (!TextUtils.equals(text, mText)) {
+ mText = text;
setVisibility(View.VISIBLE);
- setText(text);
+ setText(mText);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index f38d416..596a607 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -18,7 +18,6 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import android.annotation.Nullable;
import android.app.StatusBarManager;
import android.graphics.RectF;
import android.hardware.display.AmbientDisplayConfiguration;
@@ -44,7 +43,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShadeWindowBlurController;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -82,7 +81,7 @@
private final CommandQueue mCommandQueue;
private final NotificationShadeWindowView mView;
private final ShadeController mShadeController;
- private final NotificationShadeWindowBlurController mBlurController;
+ private final NotificationShadeDepthController mDepthController;
private GestureDetector mGestureDetector;
private View mBrightnessMirror;
@@ -126,7 +125,7 @@
CommandQueue commandQueue,
ShadeController shadeController,
DockManager dockManager,
- @Nullable NotificationShadeWindowBlurController blurController,
+ NotificationShadeDepthController depthController,
NotificationShadeWindowView notificationShadeWindowView,
NotificationPanelViewController notificationPanelViewController,
SuperStatusBarViewFactory statusBarViewFactory) {
@@ -149,7 +148,7 @@
mShadeController = shadeController;
mDockManager = dockManager;
mNotificationPanelViewController = notificationPanelViewController;
- mBlurController = blurController;
+ mDepthController = depthController;
mStatusBarViewFactory = statusBarViewFactory;
// This view is not part of the newly inflated expanded status bar.
@@ -394,10 +393,8 @@
mView.getContext(), mView, expandHelperCallback,
dragDownCallback, mFalsingManager));
- if (mBlurController != null) {
- mBlurController.setRoot(mView);
- mNotificationPanelViewController.addExpansionListener(mBlurController);
- }
+ mDepthController.setRoot(mView);
+ mNotificationPanelViewController.addExpansionListener(mDepthController);
}
public NotificationShadeWindowView getView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index b3a62d8..e6f24c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -185,15 +185,15 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -404,10 +404,9 @@
private final NotificationGutsManager mGutsManager;
private final NotificationLogger mNotificationLogger;
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final NotificationViewHierarchyManager mViewHierarchyManager;
private final KeyguardViewMediator mKeyguardViewMediator;
- private final NotificationAlertingManager mNotificationAlertingManager;
+ protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
// for disabling the status bar
private int mDisabled1 = 0;
@@ -621,10 +620,10 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
- NotificationAlertingManager notificationAlertingManager,
+ NotificationAlertingManager notificationAlertingManager, // need to inject for now
DisplayMetrics displayMetrics,
MetricsLogger metricsLogger,
@UiBackground Executor uiBgExecutor,
@@ -701,10 +700,9 @@
mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptStateProvider;
mViewHierarchyManager = notificationViewHierarchyManager;
mKeyguardViewMediator = keyguardViewMediator;
- mNotificationAlertingManager = notificationAlertingManager;
mDisplayMetrics = displayMetrics;
mMetricsLogger = metricsLogger;
mUiBgExecutor = uiBgExecutor;
@@ -1238,9 +1236,9 @@
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
mHeadsUpManager, mNotificationShadeWindowView, mStackScroller, mDozeScrimController,
mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
- mNotificationAlertingManager, mKeyguardStateController,
- mKeyguardIndicationController,
- this /* statusBar */, mShadeController, mCommandQueue, mInitController);
+ mKeyguardStateController, mKeyguardIndicationController,
+ this /* statusBar */, mShadeController, mCommandQueue, mInitController,
+ mNotificationInterruptStateProvider);
mNotificationShelf.setOnActivatedListener(mPresenter);
mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController);
@@ -1589,8 +1587,9 @@
}
if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
- mNotificationInterruptionStateProvider.setDisableNotificationAlerts(
- (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0);
+ if (areNotificationAlertsDisabled()) {
+ mHeadsUpManager.releaseAllImmediately();
+ }
}
if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
@@ -1605,6 +1604,10 @@
}
}
+ boolean areNotificationAlertsDisabled() {
+ return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
+ }
+
protected H createHandler() {
return new StatusBar.H();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index e1a20b6..53fa263 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -68,12 +68,12 @@
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
@@ -108,7 +108,7 @@
private final NotifCollection mNotifCollection;
private final FeatureFlags mFeatureFlags;
private final StatusBarStateController mStatusBarStateController;
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final MetricsLogger mMetricsLogger;
private final Context mContext;
private final NotificationPanelViewController mNotificationPanel;
@@ -142,7 +142,7 @@
NotificationLockscreenUserManager lockscreenUserManager,
ShadeController shadeController, StatusBar statusBar,
KeyguardStateController keyguardStateController,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils,
Handler mainThreadHandler, Handler backgroundHandler, Executor uiBgExecutor,
ActivityIntentHelper activityIntentHelper, BubbleController bubbleController,
@@ -167,7 +167,7 @@
mActivityStarter = activityStarter;
mEntryManager = entryManager;
mStatusBarStateController = statusBarStateController;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptStateProvider;
mMetricsLogger = metricsLogger;
mAssistManagerLazy = assistManagerLazy;
mGroupManager = groupManager;
@@ -436,7 +436,7 @@
}
private void handleFullScreenIntent(NotificationEntry entry) {
- if (mNotificationInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
+ if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
if (shouldSuppressFullScreenIntent(entry)) {
if (DEBUG) {
Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + entry.getKey());
@@ -603,7 +603,7 @@
private final ActivityIntentHelper mActivityIntentHelper;
private final BubbleController mBubbleController;
private NotificationPanelViewController mNotificationPanelViewController;
- private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final ShadeController mShadeController;
private NotificationPresenter mNotificationPresenter;
private ActivityLaunchAnimator mActivityLaunchAnimator;
@@ -626,7 +626,7 @@
NotificationGroupManager groupManager,
NotificationLockscreenUserManager lockscreenUserManager,
KeyguardStateController keyguardStateController,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
MetricsLogger metricsLogger,
LockPatternUtils lockPatternUtils,
@Main Handler mainThreadHandler,
@@ -654,7 +654,7 @@
mGroupManager = groupManager;
mLockscreenUserManager = lockscreenUserManager;
mKeyguardStateController = keyguardStateController;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptStateProvider;
mMetricsLogger = metricsLogger;
mLockPatternUtils = lockPatternUtils;
mMainThreadHandler = mainThreadHandler;
@@ -712,7 +712,7 @@
mShadeController,
mStatusBar,
mKeyguardStateController,
- mNotificationInterruptionStateProvider,
+ mNotificationInterruptStateProvider,
mMetricsLogger,
mLockPatternUtils,
mMainThreadHandler,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 30d6b507..79cea91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -60,13 +60,13 @@
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -98,8 +98,6 @@
(SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
private final NotificationEntryManager mEntryManager =
Dependency.get(NotificationEntryManager.class);
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
- Dependency.get(NotificationInterruptionStateProvider.class);
private final NotificationMediaManager mMediaManager =
Dependency.get(NotificationMediaManager.class);
private final VisualStabilityManager mVisualStabilityManager =
@@ -140,13 +138,13 @@
ScrimController scrimController,
ActivityLaunchAnimator activityLaunchAnimator,
DynamicPrivacyController dynamicPrivacyController,
- NotificationAlertingManager notificationAlertingManager,
KeyguardStateController keyguardStateController,
KeyguardIndicationController keyguardIndicationController,
StatusBar statusBar,
ShadeController shadeController,
CommandQueue commandQueue,
- InitController initController) {
+ InitController initController,
+ NotificationInterruptStateProvider notificationInterruptStateProvider) {
mContext = context;
mKeyguardStateController = keyguardStateController;
mNotificationPanel = panel;
@@ -216,8 +214,7 @@
mEntryManager.addNotificationLifetimeExtender(mGutsManager);
mEntryManager.addNotificationLifetimeExtenders(
remoteInputManager.getLifetimeExtenders());
- mNotificationInterruptionStateProvider.setUpWithPresenter(
- this, mHeadsUpManager, this::canHeadsUp);
+ notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor);
mLockscreenUserManager.setUpWithPresenter(this);
mMediaManager.setUpWithPresenter(this);
mVisualStabilityManager.setUpWithPresenter(this);
@@ -336,39 +333,6 @@
return mEntryManager.hasActiveNotifications();
}
- public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
- if (mStatusBar.isOccluded()) {
- boolean devicePublic = mLockscreenUserManager.
- isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
- boolean userPublic = devicePublic
- || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
- boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
- if (userPublic && needsRedaction) {
- // TODO(b/135046837): we can probably relax this with dynamic privacy
- return false;
- }
- }
-
- if (!mCommandQueue.panelsEnabled()) {
- if (DEBUG) {
- Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
- }
- return false;
- }
-
- if (sbn.getNotification().fullScreenIntent != null) {
- if (mAccessibilityManager.isTouchExplorationEnabled()) {
- if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
- return false;
- } else {
- // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
- return !mKeyguardStateController.isShowing()
- || mStatusBar.isOccluded();
- }
- }
- return true;
- }
-
@Override
public void onUserSwitched(int newUserId) {
// Begin old BaseStatusBar.userSwitched
@@ -507,4 +471,66 @@
}
}
};
+
+ private final NotificationInterruptSuppressor mInterruptSuppressor =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return TAG;
+ }
+
+ @Override
+ public boolean suppressAwakeHeadsUp(NotificationEntry entry) {
+ final StatusBarNotification sbn = entry.getSbn();
+ if (mStatusBar.isOccluded()) {
+ boolean devicePublic = mLockscreenUserManager
+ .isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
+ boolean userPublic = devicePublic
+ || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
+ boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
+ if (userPublic && needsRedaction) {
+ // TODO(b/135046837): we can probably relax this with dynamic privacy
+ return true;
+ }
+ }
+
+ if (!mCommandQueue.panelsEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
+ }
+ return true;
+ }
+
+ if (sbn.getNotification().fullScreenIntent != null) {
+ // we don't allow head-up on the lockscreen (unless there's a
+ // "showWhenLocked" activity currently showing) if
+ // the potential HUN has a fullscreen intent
+ if (mKeyguardStateController.isShowing() && !mStatusBar.isOccluded()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: entry has fullscreen intent on lockscreen "
+ + sbn.getKey());
+ }
+ return true;
+ }
+
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean suppressAwakeInterruptions(NotificationEntry entry) {
+ return isDeviceInVrMode();
+ }
+
+ @Override
+ public boolean suppressInterruptions(NotificationEntry entry) {
+ return mStatusBar.areNotificationAlertsDisabled();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index eec8d50..bbc7e7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -56,13 +56,13 @@
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -139,7 +139,7 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
NotificationAlertingManager notificationAlertingManager,
@@ -218,7 +218,7 @@
remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
- notificationInterruptionStateProvider,
+ notificationInterruptStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
notificationAlertingManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index cf9d8e1..24b9685 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -53,6 +53,12 @@
boolean isAodPowerSave();
/**
+ * Set reverse state.
+ * @param isReverse true if turn on reverse, false otherwise
+ */
+ default void setReverseState(boolean isReverse) {}
+
+ /**
* A listener that will be notified whenever a change in battery level or power save mode has
* occurred.
*/
@@ -63,6 +69,9 @@
default void onPowerSaveChanged(boolean isPowerSave) {
}
+
+ default void onReverseChanged(boolean isReverse, int level, String name) {
+ }
}
/**
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 d3e6f53..35954d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -59,13 +59,13 @@
private final EnhancedEstimates mEstimates;
private final BroadcastDispatcher mBroadcastDispatcher;
- private final ArrayList<BatteryController.BatteryStateChangeCallback>
+ protected final ArrayList<BatteryController.BatteryStateChangeCallback>
mChangeCallbacks = new ArrayList<>();
private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
private final Handler mMainHandler;
private final Handler mBgHandler;
- private final Context mContext;
+ protected final Context mContext;
private int mLevel;
private boolean mPluggedIn;
@@ -80,7 +80,7 @@
@VisibleForTesting
@Inject
- BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
+ protected BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
PowerManager powerManager, BroadcastDispatcher broadcastDispatcher,
@Main Handler mainHandler, @Background Handler bgHandler) {
mContext = context;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 759bad4..812ce1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -236,7 +236,7 @@
String action = intent.getAction();
if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
- String tz = intent.getStringExtra("time-zone");
+ String tz = intent.getStringExtra(Intent.EXTRA_TIMEZONE);
handler.post(() -> {
mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
if (mClockFormat != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index b84208c..99709402 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -630,7 +630,7 @@
@VisibleForTesting
void doUpdateMobileControllers() {
List<SubscriptionInfo> subscriptions = mSubscriptionManager
- .getActiveAndHiddenSubscriptionInfoList();
+ .getCompleteActiveSubscriptionInfoList();
if (subscriptions == null) {
subscriptions = Collections.emptyList();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
index 74739e1..e70e30a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
@@ -24,6 +24,7 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.IntDef;
+import android.annotation.UiThread;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -43,7 +44,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
@@ -98,8 +98,27 @@
private TextView mTextView;
@State private int mState = STATE_NOT_SHOWN;
- private final Set<String> mAudioRecordingApps = new HashSet<>();
- private final Queue<String> mPendingNotifications = new LinkedList<>();
+ /**
+ * Set of the applications that currently are conducting audio recording.
+ */
+ private final Set<String> mActiveAudioRecordingPackages = new ArraySet<>();
+ /**
+ * Set of applications that we've notified the user about since the indicator came up. Meaning
+ * that if an application is in this list then at some point since the indicator came up, it
+ * was expanded showing this application's title.
+ * Used not to notify the user about the same application again while the indicator is shown.
+ * We empty this set every time the indicator goes off the screen (we always call {@code
+ * mSessionNotifiedPackages.clear()} before calling {@link #hide()}).
+ */
+ private final Set<String> mSessionNotifiedPackages = new ArraySet<>();
+ /**
+ * If an application starts recording while the TV indicator is neither in {@link
+ * #STATE_NOT_SHOWN} nor in {@link #STATE_MINIMIZED}, then we add the application's package
+ * name to the queue, from which we take packages names one by one to disclose the
+ * corresponding applications' titles to the user, whenever the indicator eventually comes to
+ * one of the two aforementioned states.
+ */
+ private final Queue<String> mPendingNotificationPackages = new LinkedList<>();
AudioRecordingDisclosureBar(Context context) {
mContext = context;
@@ -115,11 +134,16 @@
new OnActiveRecordingListener());
}
+ @UiThread
private void onStartedRecording(String packageName) {
- if (!mAudioRecordingApps.add(packageName)) {
+ if (!mActiveAudioRecordingPackages.add(packageName)) {
// This app is already known to perform recording
return;
}
+ if (!mSessionNotifiedPackages.add(packageName)) {
+ // We've already notified user about this app, no need to do it again.
+ return;
+ }
switch (mState) {
case STATE_NOT_SHOWN:
@@ -137,13 +161,14 @@
case STATE_MINIMIZING:
// Currently animating or expanded. Thus add to the pending notifications, and it
// will be picked up once the indicator comes to the STATE_MINIMIZED.
- mPendingNotifications.add(packageName);
+ mPendingNotificationPackages.add(packageName);
break;
}
}
+ @UiThread
private void onDoneRecording(String packageName) {
- if (!mAudioRecordingApps.remove(packageName)) {
+ if (!mActiveAudioRecordingPackages.remove(packageName)) {
// Was not marked as an active recorder, do nothing
return;
}
@@ -151,11 +176,13 @@
// If not MINIMIZED, will check whether the indicator should be hidden when the indicator
// comes to the STATE_MINIMIZED eventually. If is in the STATE_MINIMIZED, but there are
// other active recorders - simply ignore.
- if (mState == STATE_MINIMIZED && mAudioRecordingApps.isEmpty()) {
+ if (mState == STATE_MINIMIZED && mActiveAudioRecordingPackages.isEmpty()) {
+ mSessionNotifiedPackages.clear();
hide();
}
}
+ @UiThread
private void show(String packageName) {
// Inflate the indicator view
mIndicatorView = LayoutInflater.from(mContext).inflate(
@@ -230,6 +257,7 @@
mState = STATE_APPEARING;
}
+ @UiThread
private void expand(String packageName) {
final String label = getApplicationLabel(packageName);
mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
@@ -253,6 +281,7 @@
mState = STATE_MAXIMIZING;
}
+ @UiThread
private void minimize() {
final int targetOffset = mTextsContainers.getWidth();
final AnimatorSet set = new AnimatorSet();
@@ -274,6 +303,7 @@
mState = STATE_MINIMIZING;
}
+ @UiThread
private void hide() {
final int targetOffset =
mIndicatorView.getWidth() - (int) mIconTextsContainer.getTranslationX();
@@ -294,24 +324,28 @@
mState = STATE_DISAPPEARING;
}
+ @UiThread
private void onExpanded() {
mState = STATE_SHOWN;
mIndicatorView.postDelayed(this::minimize, MAXIMIZED_DURATION);
}
+ @UiThread
private void onMinimized() {
mState = STATE_MINIMIZED;
- if (!mPendingNotifications.isEmpty()) {
+ if (!mPendingNotificationPackages.isEmpty()) {
// There is a new application that started recording, tell the user about it.
- expand(mPendingNotifications.poll());
- } else if (mAudioRecordingApps.isEmpty()) {
- // Nobody is recording anymore, remove the indicator.
+ expand(mPendingNotificationPackages.poll());
+ } else if (mActiveAudioRecordingPackages.isEmpty()) {
+ // Nobody is recording anymore, clear state and remove the indicator.
+ mSessionNotifiedPackages.clear();
hide();
}
}
+ @UiThread
private void onHidden() {
final WindowManager windowManager = (WindowManager) mContext.getSystemService(
Context.WINDOW_SERVICE);
@@ -326,8 +360,15 @@
mBgRight = null;
mState = STATE_NOT_SHOWN;
+
+ // Check if anybody started recording while we were in STATE_DISAPPEARING
+ if (!mPendingNotificationPackages.isEmpty()) {
+ // There is a new application that started recording, tell the user about it.
+ show(mPendingNotificationPackages.poll());
+ }
}
+ @UiThread
private void startPulsatingAnimation() {
final View pulsatingView = mIconTextsContainer.findViewById(R.id.pulsating_circle);
final ObjectAnimator animator =
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 30db37c..f31f8eb 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -43,6 +43,7 @@
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -101,7 +102,7 @@
new ContentObserver(mBgHandler) {
@Override
- public void onChange(boolean selfChange, Iterable<Uri> uris, int flags,
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags,
int userId) {
if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId);
if (ActivityManager.getCurrentUser() == userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index b2a5f5b..248bdc8 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -41,9 +41,9 @@
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.util.leak.LeakDetector;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -69,7 +69,8 @@
// Map of Uris we listen on to their settings keys.
private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
// Map of settings keys to the listener.
- private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
+ private final ConcurrentHashMap<String, Set<Tunable>> mTunableLookup =
+ new ConcurrentHashMap<>();
// Set of all tunables, used for leak detection.
private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null;
private final Context mContext;
@@ -262,7 +263,8 @@
}
@Override
- public void onChange(boolean selfChange, Iterable<Uri> uris, int flags, int userId) {
+ public void onChange(boolean selfChange, java.util.Collection<Uri> uris,
+ int flags, int userId) {
if (userId == ActivityManager.getCurrentUser()) {
for (Uri u : uris) {
reloadSetting(u);
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
index 23df991..ccb8699 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -324,7 +324,7 @@
@Override
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync) {}
+ float zoom, boolean sync) {}
@Override
public void dispatchWallpaperCommand(String action, int x, int y,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index ea6cf33..f7daf97 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -249,7 +249,7 @@
// STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
// same answer as KeyguardUpdateMonitor. Remove when this is addressed
- when(mSubscriptionManager.getActiveAndHiddenSubscriptionInfoList()).thenReturn(
+ when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(
new ArrayList<>());
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index eead120..4f4ce13 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -516,7 +516,7 @@
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION);
list.add(TEST_SUBSCRIPTION_2);
- when(mSubscriptionManager.getActiveAndHiddenSubscriptionInfoList()).thenReturn(list);
+ when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(list);
mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged(
TEST_SUBSCRIPTION_2.getSubscriptionId());
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index 6199181..353fe62 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -50,6 +50,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
// Need to run tests on main looper because LiveData operations such as setData, observe,
@@ -126,7 +128,7 @@
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(null);
when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(null);
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the result is null, indicated the default clock face should be used.
assertThat(mClockManager.getCurrentClock()).isNull();
}
@@ -136,7 +138,7 @@
// GIVEN that settings is set to the bubble clock face
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the plugin is the bubble clock face.
assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
}
@@ -146,7 +148,7 @@
// GIVEN that settings is set to the bubble clock face
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the plugin is the bubble clock face.
ArgumentCaptor<ClockPlugin> captor = ArgumentCaptor.forClass(ClockPlugin.class);
verify(mMockListener1).onClockChanged(captor.capture());
@@ -158,7 +160,7 @@
// GIVEN that settings is set to the bubble clock face
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the listeners receive separate instances of the Bubble clock plugin.
ArgumentCaptor<ClockPlugin> captor1 = ArgumentCaptor.forClass(ClockPlugin.class);
ArgumentCaptor<ClockPlugin> captor2 = ArgumentCaptor.forClass(ClockPlugin.class);
@@ -175,7 +177,7 @@
// custom clock face.
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn("bad value");
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the result is null.
assertThat(mClockManager.getCurrentClock()).isNull();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 78160c4..6e612d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -45,7 +45,11 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.res.Resources;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.face.FaceManager;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.service.dreams.IDreamManager;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -61,14 +65,12 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -227,15 +229,17 @@
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
- TestableNotificationInterruptionStateProvider interruptionStateProvider =
- new TestableNotificationInterruptionStateProvider(mContext,
+ TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
+ new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
+ mock(PowerManager.class),
+ mock(IDreamManager.class),
+ mock(AmbientDisplayConfiguration.class),
mock(NotificationFilter.class),
mock(StatusBarStateController.class),
- mock(BatteryController.class));
- interruptionStateProvider.setUpWithPresenter(
- mock(NotificationPresenter.class),
- mock(HeadsUpManager.class),
- mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
+ mock(BatteryController.class),
+ mock(HeadsUpManager.class),
+ mock(Handler.class)
+ );
mBubbleData = new BubbleData(mContext);
when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mBubbleController = new TestableBubbleController(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
index 5ef4cd2..6244644 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -41,7 +41,11 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.res.Resources;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.face.FaceManager;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.service.dreams.IDreamManager;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -57,12 +61,10 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -212,15 +214,17 @@
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
- TestableNotificationInterruptionStateProvider interruptionStateProvider =
- new TestableNotificationInterruptionStateProvider(mContext,
+ TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
+ new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
+ mock(PowerManager.class),
+ mock(IDreamManager.class),
+ mock(AmbientDisplayConfiguration.class),
mock(NotificationFilter.class),
mock(StatusBarStateController.class),
- mock(BatteryController.class));
- interruptionStateProvider.setUpWithPresenter(
- mock(NotificationPresenter.class),
- mock(HeadsUpManager.class),
- mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
+ mock(BatteryController.class),
+ mock(HeadsUpManager.class),
+ mock(Handler.class)
+ );
mBubbleData = new BubbleData(mContext);
when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
mBubbleController = new TestableBubbleController(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
index de1fb41..d3d90c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -23,8 +23,8 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -44,7 +44,7 @@
ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
- NotificationInterruptionStateProvider interruptionStateProvider,
+ NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
NotificationGroupManager groupManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java
new file mode 100644
index 0000000..17dc76b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.systemui.bubbles;
+
+import android.content.ContentResolver;
+import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.service.dreams.IDreamManager;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+public class TestableNotificationInterruptStateProviderImpl
+ extends NotificationInterruptStateProviderImpl {
+
+ TestableNotificationInterruptStateProviderImpl(
+ ContentResolver contentResolver,
+ PowerManager powerManager,
+ IDreamManager dreamManager,
+ AmbientDisplayConfiguration ambientDisplayConfiguration,
+ NotificationFilter filter,
+ StatusBarStateController statusBarStateController,
+ BatteryController batteryController,
+ HeadsUpManager headsUpManager,
+ Handler mainHandler) {
+ super(contentResolver,
+ powerManager,
+ dreamManager,
+ ambientDisplayConfiguration,
+ filter,
+ batteryController,
+ statusBarStateController,
+ headsUpManager,
+ mainHandler);
+ mUseHeadsUp = true;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java
deleted file mode 100644
index 5d192b2..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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.systemui.bubbles;
-
-import android.content.Context;
-
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.policy.BatteryController;
-
-public class TestableNotificationInterruptionStateProvider
- extends NotificationInterruptionStateProvider {
-
- TestableNotificationInterruptionStateProvider(Context context,
- NotificationFilter filter, StatusBarStateController controller,
- BatteryController batteryController) {
- super(context, filter, controller, batteryController);
- mUseHeadsUp = true;
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index eceb1dd..c25d4e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -22,6 +22,8 @@
import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.DeviceTypes
+import android.service.controls.IControlsSubscriber
+import android.service.controls.IControlsSubscription
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -34,6 +36,8 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.`when`
@@ -48,6 +52,7 @@
class ControlsBindingControllerImplTest : SysuiTestCase() {
companion object {
+ fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
fun <T> any(): T = Mockito.any<T>()
private val TEST_COMPONENT_NAME_1 = ComponentName("TEST_PKG", "TEST_CLS_1")
private val TEST_COMPONENT_NAME_2 = ComponentName("TEST_PKG", "TEST_CLS_2")
@@ -57,6 +62,15 @@
@Mock
private lateinit var mockControlsController: ControlsController
+ @Captor
+ private lateinit var subscriberCaptor: ArgumentCaptor<IControlsSubscriber.Stub>
+
+ @Captor
+ private lateinit var loadSubscriberCaptor: ArgumentCaptor<IControlsSubscriber.Stub>
+
+ @Captor
+ private lateinit var listStringCaptor: ArgumentCaptor<List<String>>
+
private val user = UserHandle.of(mContext.userId)
private val otherUser = UserHandle.of(user.identifier + 1)
@@ -97,6 +111,102 @@
}
@Test
+ fun testBindAndLoad_cancel() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(loadSubscriberCaptor))
+ loadSubscriberCaptor.value.onSubscribe(Binder(), subscription)
+
+ canceller.run()
+ verify(subscription).cancel()
+ }
+
+ @Test
+ fun testBindAndLoad_noCancelAfterOnComplete() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(loadSubscriberCaptor))
+ val b = Binder()
+ loadSubscriberCaptor.value.onSubscribe(b, subscription)
+
+ loadSubscriberCaptor.value.onComplete(b)
+ canceller.run()
+ verify(subscription, never()).cancel()
+ }
+
+ @Test
+ fun testLoad_onCompleteRemovesTimeout() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(subscriberCaptor))
+ val b = Binder()
+ subscriberCaptor.value.onSubscribe(b, subscription)
+
+ subscriberCaptor.value.onComplete(b)
+ verify(providers[0]).cancelLoadTimeout()
+ }
+
+ @Test
+ fun testLoad_onErrorRemovesTimeout() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(subscriberCaptor))
+ val b = Binder()
+ subscriberCaptor.value.onSubscribe(b, subscription)
+
+ subscriberCaptor.value.onError(b, "")
+ verify(providers[0]).cancelLoadTimeout()
+ }
+
+ @Test
+ fun testBindAndLoad_noCancelAfterOnError() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(loadSubscriberCaptor))
+ val b = Binder()
+ loadSubscriberCaptor.value.onSubscribe(b, subscription)
+
+ loadSubscriberCaptor.value.onError(b, "")
+ canceller.run()
+ verify(subscription, never()).cancel()
+ }
+
+ @Test
fun testBindService() {
controller.bindService(TEST_COMPONENT_NAME_1)
executor.runAllReady()
@@ -115,8 +225,13 @@
executor.runAllReady()
+ val subs = mock(IControlsSubscription::class.java)
verify(providers[0]).maybeBindAndSubscribe(
+ capture(listStringCaptor), capture(subscriberCaptor))
+ assertEquals(listStringCaptor.value,
listOf(controlInfo1.controlId, controlInfo2.controlId))
+
+ subscriberCaptor.value.onSubscribe(providers[0].token, subs)
}
@Test
@@ -126,7 +241,7 @@
executor.runAllReady()
- verify(providers[0], never()).unsubscribe()
+ verify(providers[0], never()).cancelSubscription(any())
}
@Test
@@ -137,12 +252,21 @@
StructureInfo(TEST_COMPONENT_NAME_1, "Home", listOf(controlInfo1, controlInfo2))
controller.subscribe(structure)
-
- controller.unsubscribe()
-
executor.runAllReady()
- verify(providers[0]).unsubscribe()
+ val subs = mock(IControlsSubscription::class.java)
+ verify(providers[0]).maybeBindAndSubscribe(
+ capture(listStringCaptor), capture(subscriberCaptor))
+ assertEquals(listStringCaptor.value,
+ listOf(controlInfo1.controlId, controlInfo2.controlId))
+
+ subscriberCaptor.value.onSubscribe(providers[0].token, subs)
+ executor.runAllReady()
+
+ controller.unsubscribe()
+ executor.runAllReady()
+
+ verify(providers[0]).cancelSubscription(subs)
}
@Test
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 a8c4851..f9c9815 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
@@ -234,7 +234,7 @@
loaded = true
assertEquals(1, controls.size)
val controlStatus = controls[0]
- assertEquals(ControlStatus(control, false), controlStatus)
+ assertEquals(ControlStatus(control, TEST_COMPONENT, false), controlStatus)
assertTrue(favorites.isEmpty())
assertFalse(data.errorOnLoad)
@@ -265,10 +265,10 @@
loaded = true
assertEquals(2, controls.size)
val controlStatus = controls.first { it.control.controlId == TEST_CONTROL_ID }
- assertEquals(ControlStatus(control, true), controlStatus)
+ assertEquals(ControlStatus(control, TEST_COMPONENT, true), controlStatus)
val controlStatus2 = controls.first { it.control.controlId == TEST_CONTROL_ID_2 }
- assertEquals(ControlStatus(control2, false), controlStatus2)
+ assertEquals(ControlStatus(control2, TEST_COMPONENT, false), controlStatus2)
assertEquals(1, favorites.size)
assertEquals(TEST_CONTROL_ID, favorites[0])
@@ -346,6 +346,88 @@
}
@Test
+ fun testCancelLoad() {
+ val canceller = object : Runnable {
+ var ran = false
+ override fun run() {
+ ran = true
+ }
+ }
+ `when`(bindingController.bindAndLoad(any(), any())).thenReturn(canceller)
+
+ var loaded = false
+ controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
+ delayableExecutor.runAllReady()
+ controller.loadForComponent(TEST_COMPONENT, Consumer {
+ loaded = true
+ })
+
+ controller.cancelLoad()
+ delayableExecutor.runAllReady()
+
+ assertFalse(loaded)
+ assertTrue(canceller.ran)
+ }
+
+ @Test
+ fun testCancelLoad_noCancelAfterSuccessfulLoad() {
+ val canceller = object : Runnable {
+ var ran = false
+ override fun run() {
+ ran = true
+ }
+ }
+ `when`(bindingController.bindAndLoad(any(), any())).thenReturn(canceller)
+
+ var loaded = false
+ controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
+ delayableExecutor.runAllReady()
+ controller.loadForComponent(TEST_COMPONENT, Consumer {
+ loaded = true
+ })
+
+ verify(bindingController).bindAndLoad(eq(TEST_COMPONENT),
+ capture(controlLoadCallbackCaptor))
+
+ controlLoadCallbackCaptor.value.accept(emptyList())
+
+ controller.cancelLoad()
+ delayableExecutor.runAllReady()
+
+ assertTrue(loaded)
+ assertFalse(canceller.ran)
+ }
+
+ @Test
+ fun testCancelLoad_noCancelAfterErrorLoad() {
+ val canceller = object : Runnable {
+ var ran = false
+ override fun run() {
+ ran = true
+ }
+ }
+ `when`(bindingController.bindAndLoad(any(), any())).thenReturn(canceller)
+
+ var loaded = false
+ controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
+ delayableExecutor.runAllReady()
+ controller.loadForComponent(TEST_COMPONENT, Consumer {
+ loaded = true
+ })
+
+ verify(bindingController).bindAndLoad(eq(TEST_COMPONENT),
+ capture(controlLoadCallbackCaptor))
+
+ controlLoadCallbackCaptor.value.error("")
+
+ controller.cancelLoad()
+ delayableExecutor.runAllReady()
+
+ assertTrue(loaded)
+ assertFalse(canceller.ran)
+ }
+
+ @Test
fun testFavoriteInformationModifiedOnLoad() {
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
delayableExecutor.runAllReady()
@@ -521,7 +603,7 @@
}
@Test
- fun testReplaceFavoritesForStructure_noFavorites() {
+ fun testReplaceFavoritesForStructure_noExistingFavorites() {
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
delayableExecutor.runAllReady()
@@ -531,6 +613,16 @@
}
@Test
+ fun testReplaceFavoritesForStructure_doNotStoreEmptyStructure() {
+ controller.replaceFavoritesForStructure(
+ StructureInfo(TEST_COMPONENT, "Home", emptyList<ControlInfo>()))
+ delayableExecutor.runAllReady()
+
+ assertEquals(0, controller.countFavoritesForComponent(TEST_COMPONENT))
+ assertEquals(emptyList<ControlInfo>(), controller.getFavoritesForComponent(TEST_COMPONENT))
+ }
+
+ @Test
fun testReplaceFavoritesForStructure_differentComponentsAreFilteredOut() {
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO_2)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index fd92ad0..2d3757c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
+ * Licensed under the Apache License, Version 2.0 (149the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
@@ -43,6 +43,7 @@
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -83,7 +84,6 @@
context,
executor,
actionCallbackService,
- subscriberService,
UserHandle.of(0),
componentName
)
@@ -144,9 +144,22 @@
}
@Test
+ fun testMaybeBindAndLoad_timeoutCancelled() {
+ manager.maybeBindAndLoad(subscriberService)
+ executor.runAllReady()
+
+ manager.cancelLoadTimeout()
+
+ executor.advanceClockToLast()
+ executor.runAllReady()
+
+ verify(subscriberService, never()).onError(any(), anyString())
+ }
+
+ @Test
fun testMaybeBindAndSubscribe() {
val list = listOf("TEST_ID")
- manager.maybeBindAndSubscribe(list)
+ manager.maybeBindAndSubscribe(list, subscriberService)
executor.runAllReady()
assertTrue(mContext.isBound(componentName))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
new file mode 100644
index 0000000..ff5c8d4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
@@ -0,0 +1,146 @@
+/*
+ * 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.systemui.controls.controller
+
+import android.content.ComponentName
+import android.os.Binder
+import android.service.controls.Control
+import android.service.controls.IControlsSubscription
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class StatefulControlSubscriberTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var controller: ControlsController
+
+ @Mock
+ private lateinit var subscription: IControlsSubscription
+
+ @Mock
+ private lateinit var provider: ControlsProviderLifecycleManager
+
+ @Mock
+ private lateinit var control: Control
+
+ private val executor = FakeExecutor(FakeSystemClock())
+ private val token = Binder()
+ private val badToken = Binder()
+
+ private val TEST_COMPONENT = ComponentName("TEST_PKG", "TEST_CLS_1")
+
+ private lateinit var scs: StatefulControlSubscriber
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ `when`(provider.componentName).thenReturn(TEST_COMPONENT)
+ `when`(provider.token).thenReturn(token)
+ scs = StatefulControlSubscriber(controller, provider, executor)
+ }
+
+ @Test
+ fun testOnSubscribe() {
+ scs.onSubscribe(token, subscription)
+
+ executor.runAllReady()
+ verify(provider).startSubscription(subscription)
+ }
+
+ @Test
+ fun testOnSubscribe_badToken() {
+ scs.onSubscribe(badToken, subscription)
+
+ executor.runAllReady()
+ verify(provider, never()).startSubscription(subscription)
+ }
+
+ @Test
+ fun testOnNext() {
+ scs.onSubscribe(token, subscription)
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_multiple() {
+ scs.onSubscribe(token, subscription)
+ scs.onNext(token, control)
+ scs.onNext(token, control)
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, times(3)).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_noRefreshBeforeSubscribe() {
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, never()).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_noRefreshAfterCancel() {
+ scs.onSubscribe(token, subscription)
+ executor.runAllReady()
+
+ scs.cancel()
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, never()).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_noRefreshAfterError() {
+ scs.onSubscribe(token, subscription)
+ scs.onError(token, "Error")
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, never()).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_noRefreshAfterComplete() {
+ scs.onSubscribe(token, subscription)
+ scs.onComplete(token)
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, never()).refreshStatus(TEST_COMPONENT, control)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
index 68e1ec1..133df2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.management
import android.app.PendingIntent
+import android.content.ComponentName
import android.service.controls.Control
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
@@ -78,6 +79,7 @@
Control.StatelessBuilder("$idPrefix$it", pendingIntent)
.setZone(zoneMap(it))
.build(),
+ ComponentName("", ""),
it in favoritesIndices
)
}
@@ -189,4 +191,4 @@
assertTrue(sameControl(it.first, it.second))
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 85e937e..13a7708 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -30,7 +30,6 @@
import com.android.systemui.util.time.FakeSystemClock
import org.junit.After
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -38,6 +37,7 @@
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -98,74 +98,18 @@
}
@Test
+ fun testInitialStateListening() {
+ verify(mockSL).setListening(true)
+ verify(mockSL).reload()
+ }
+
+ @Test
fun testStartsOnUser() {
assertEquals(user, controller.currentUserId)
}
@Test
- fun testNoServices_notListening() {
- assertTrue(controller.getCurrentServices().isEmpty())
- }
-
- @Test
- fun testStartListening_onFirstCallback() {
- controller.addCallback(mockCallback)
- executor.runAllReady()
-
- verify(mockSL).setListening(true)
- }
-
- @Test
- fun testStartListening_onlyOnce() {
- controller.addCallback(mockCallback)
- controller.addCallback(mockCallbackOther)
-
- executor.runAllReady()
-
- verify(mockSL).setListening(true)
- }
-
- @Test
- fun testStopListening_callbackRemoved() {
- controller.addCallback(mockCallback)
-
- executor.runAllReady()
-
- controller.removeCallback(mockCallback)
-
- executor.runAllReady()
-
- verify(mockSL).setListening(false)
- }
-
- @Test
- fun testStopListening_notWhileRemainingCallbacks() {
- controller.addCallback(mockCallback)
- controller.addCallback(mockCallbackOther)
-
- executor.runAllReady()
-
- controller.removeCallback(mockCallback)
-
- executor.runAllReady()
-
- verify(mockSL, never()).setListening(false)
- }
-
- @Test
- fun testReloadOnFirstCallbackAdded() {
- controller.addCallback(mockCallback)
- executor.runAllReady()
-
- verify(mockSL).reload()
- }
-
- @Test
fun testCallbackCalledWhenAdded() {
- `when`(mockSL.reload()).then {
- serviceListingCallbackCaptor.value.onServicesReloaded(emptyList())
- }
-
controller.addCallback(mockCallback)
executor.runAllReady()
verify(mockCallback).onServicesUpdated(any())
@@ -209,5 +153,11 @@
controller.changeUser(UserHandle.of(otherUser))
executor.runAllReady()
assertEquals(otherUser, controller.currentUserId)
+
+ val inOrder = inOrder(mockSL)
+ inOrder.verify(mockSL).setListening(false)
+ inOrder.verify(mockSL).addCallback(any()) // We add a callback because we replaced the SL
+ inOrder.verify(mockSL).setListening(true)
+ inOrder.verify(mockSL).reload()
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt
index 9ffc29e..c330b38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.management
import android.app.PendingIntent
+import android.content.ComponentName
import android.service.controls.Control
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
@@ -70,6 +71,7 @@
Control.StatelessBuilder("$idPrefix$it", pendingIntent)
.setZone((it % 3).toString())
.build(),
+ ComponentName("", ""),
it in favoritesIndices
)
}
@@ -195,4 +197,4 @@
verifyNoMoreInteractions(allAdapter, favoritesAdapter)
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 0098012..73f3ddd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -22,7 +22,9 @@
import static junit.framework.TestCase.assertFalse;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -137,6 +139,8 @@
return new TestTile1(mQSTileHost);
} else if ("spec2".equals(spec)) {
return new TestTile2(mQSTileHost);
+ } else if ("na".equals(spec)) {
+ return new NotAvailableTile(mQSTileHost);
} else if (CUSTOM_TILE_SPEC.equals(spec)) {
return mCustomTile;
} else {
@@ -283,6 +287,12 @@
assertEquals(1, specs.size());
}
+ @Test
+ public void testNotAvailableTile_specNotNull() {
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "na");
+ verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString());
+ }
+
private static class TestQSTileHost extends QSTileHost {
TestQSTileHost(Context context, StatusBarIconController iconController,
QSFactoryImpl defaultFactory, Handler mainHandler, Looper bgLooper,
@@ -369,4 +379,16 @@
super(host);
}
}
+
+ private class NotAvailableTile extends TestTile {
+
+ protected NotAvailableTile(QSHost host) {
+ super(host);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return false;
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
index 62f406f..1b0ed11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
@@ -22,6 +22,8 @@
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
+import com.android.internal.logging.InstanceId;
+
/**
* Convenience builder for {@link StatusBarNotification} since its constructor is terrifying.
*
@@ -40,6 +42,7 @@
private UserHandle mUser = UserHandle.of(0);
private String mOverrideGroupKey;
private long mPostTime;
+ private InstanceId mInstanceId;
public SbnBuilder() {
}
@@ -55,6 +58,7 @@
mUser = source.getUser();
mOverrideGroupKey = source.getOverrideGroupKey();
mPostTime = source.getPostTime();
+ mInstanceId = source.getInstanceId();
}
public StatusBarNotification build() {
@@ -71,7 +75,7 @@
notification.setBubbleMetadata(mBubbleMetadata);
}
- return new StatusBarNotification(
+ StatusBarNotification result = new StatusBarNotification(
mPkg,
mOpPkg,
mId,
@@ -82,6 +86,10 @@
mUser,
mOverrideGroupKey,
mPostTime);
+ if (mInstanceId != null) {
+ result.setInstanceId(mInstanceId);
+ }
+ return result;
}
public SbnBuilder setPkg(String pkg) {
@@ -175,4 +183,9 @@
mBubbleMetadata = data;
return this;
}
+
+ public SbnBuilder setInstanceId(InstanceId instanceId) {
+ mInstanceId = instanceId;
+ return this;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 92a9080..261dc82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -26,6 +26,7 @@
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
+import com.android.internal.logging.InstanceId;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
@@ -141,6 +142,11 @@
return this;
}
+ public NotificationEntryBuilder setInstanceId(InstanceId instanceId) {
+ mSbnBuilder.setInstanceId(instanceId);
+ return this;
+ }
+
/* Delegated to Notification.Builder (via SbnBuilder) */
public NotificationEntryBuilder setContentTitle(Context context, String contentTitle) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
similarity index 63%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 1693e7f..f9c62e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.notification.interruption;
import static android.app.Notification.FLAG_BUBBLE;
@@ -30,15 +30,14 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.PendingIntent;
-import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
@@ -50,7 +49,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -68,7 +66,7 @@
*/
@RunWith(AndroidTestingRunner.class)
@SmallTest
-public class NotificationInterruptionStateProviderTest extends SysuiTestCase {
+public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
@Mock
PowerManager mPowerManager;
@@ -81,38 +79,36 @@
@Mock
StatusBarStateController mStatusBarStateController;
@Mock
- NotificationPresenter mPresenter;
- @Mock
HeadsUpManager mHeadsUpManager;
@Mock
- NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
- @Mock
BatteryController mBatteryController;
+ @Mock
+ Handler mMockHandler;
- private NotificationInterruptionStateProvider mNotifInterruptionStateProvider;
+ private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mNotifInterruptionStateProvider =
- new TestableNotificationInterruptionStateProvider(mContext,
+ new NotificationInterruptStateProviderImpl(
+ mContext.getContentResolver(),
mPowerManager,
mDreamManager,
mAmbientDisplayConfiguration,
mNotificationFilter,
+ mBatteryController,
mStatusBarStateController,
- mBatteryController);
+ mHeadsUpManager,
+ mMockHandler);
- mNotifInterruptionStateProvider.setUpWithPresenter(
- mPresenter,
- mHeadsUpManager,
- mHeadsUpSuppressor);
+ mNotifInterruptionStateProvider.mUseHeadsUp = true;
}
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#canAlertCommon(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#canAlertCommon(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills group suppression check.
*/
private void ensureStateForAlertCommon() {
@@ -121,17 +117,16 @@
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#canAlertAwakeCommon(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#canAlertAwakeCommon(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills launch fullscreen check.
*/
private void ensureStateForAlertAwakeCommon() {
- when(mPresenter.isDeviceInVrMode()).thenReturn(false);
when(mHeadsUpManager.isSnoozed(any())).thenReturn(false);
}
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills importance & DND checks.
*/
private void ensureStateForHeadsUpWhenAwake() throws RemoteException {
@@ -141,12 +136,11 @@
when(mStatusBarStateController.isDozing()).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
when(mPowerManager.isScreenOn()).thenReturn(true);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
}
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills importance & DND checks.
*/
private void ensureStateForHeadsUpWhenDozing() {
@@ -158,7 +152,7 @@
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#shouldBubbleUp(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#shouldBubbleUp(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills importance & bubble checks.
*/
private void ensureStateForBubbleUp() {
@@ -166,75 +160,53 @@
ensureStateForAlertAwakeCommon();
}
- /**
- * Ensure that the disabled state is set correctly.
- */
@Test
- public void testDisableNotificationAlerts() {
- // Enabled by default
- assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse();
-
- // Disable alerts
- mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
- assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isTrue();
-
- // Enable alerts
- mNotifInterruptionStateProvider.setDisableNotificationAlerts(false);
- assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse();
- }
-
- /**
- * Ensure that the disabled alert state effects whether HUNs are enabled.
- */
- @Test
- public void testHunSettingsChange_enabled_butAlertsDisabled() {
- // Set up but without a mock change observer
- mNotifInterruptionStateProvider.setUpWithPresenter(
- mPresenter,
- mHeadsUpManager,
- mHeadsUpSuppressor);
-
- // HUNs enabled by default
- assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isTrue();
-
- // Set alerts disabled
- mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
-
- // No more HUNs
- assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse();
- }
-
- /**
- * Alerts can happen.
- */
- @Test
- public void testCanAlertCommon_true() {
- ensureStateForAlertCommon();
+ public void testDefaultSuppressorDoesNotSuppress() {
+ // GIVEN a suppressor without any overrides
+ final NotificationInterruptSuppressor defaultSuppressor =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return "defaultSuppressor";
+ }
+ };
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
- assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isTrue();
+
+ // THEN this suppressor doesn't suppress anything by default
+ assertThat(defaultSuppressor.suppressAwakeHeadsUp(entry)).isFalse();
+ assertThat(defaultSuppressor.suppressAwakeInterruptions(entry)).isFalse();
+ assertThat(defaultSuppressor.suppressInterruptions(entry)).isFalse();
}
- /**
- * Filtered out notifications don't alert.
- */
@Test
- public void testCanAlertCommon_false_filteredOut() {
- ensureStateForAlertCommon();
- when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
+ public void testShouldHeadsUpAwake() throws RemoteException {
+ ensureStateForHeadsUpWhenAwake();
- NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
- assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse();
+ NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
}
- /**
- * Grouped notifications have different alerting behaviours, sometimes the alert for a
- * grouped notification may be suppressed {@link android.app.Notification#GROUP_ALERT_CHILDREN}.
- */
@Test
- public void testCanAlertCommon_false_suppressedForGroups() {
- ensureStateForAlertCommon();
+ public void testShouldNotHeadsUpAwake_flteredOut() throws RemoteException {
+ // GIVEN state for "heads up when awake" is true
+ ensureStateForHeadsUpWhenAwake();
+ // WHEN this entry should be filtered out
+ NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+ when(mNotificationFilter.shouldFilterOut(entry)).thenReturn(true);
+
+ // THEN we shouldn't heads up this entry
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+ }
+
+ @Test
+ public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException {
+ // GIVEN state for "heads up when awake" is true
+ ensureStateForHeadsUpWhenAwake();
+
+ // WHEN the alert for a grouped notification is suppressed
+ // see {@link android.app.Notification#GROUP_ALERT_CHILDREN}
NotificationEntry entry = new NotificationEntryBuilder()
.setPkg("a")
.setOpPkg("a")
@@ -247,40 +219,40 @@
.setImportance(IMPORTANCE_DEFAULT)
.build();
- assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse();
+ // THEN this entry shouldn't HUN
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * HUNs while dozing can happen.
- */
@Test
- public void testShouldHeadsUpWhenDozing_true() {
+ public void testShouldHeadsUpWhenDozing() {
ensureStateForHeadsUpWhenDozing();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
}
- /**
- * Ambient display can show HUNs for new notifications, this may be disabled.
- */
@Test
- public void testShouldHeadsUpWhenDozing_false_pulseDisabled() {
+ public void testShouldNotHeadsUpWhenDozing_pulseDisabled() {
+ // GIVEN state for "heads up when dozing" is true
ensureStateForHeadsUpWhenDozing();
+
+ // WHEN pulsing (HUNs when dozing) is disabled
when(mAmbientDisplayConfiguration.pulseOnNotificationEnabled(anyInt())).thenReturn(false);
+ // THEN this entry shouldn't HUN
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * If the device is not in ambient display or sleeping then we don't HUN.
- */
@Test
- public void testShouldHeadsUpWhenDozing_false_notDozing() {
+ public void testShouldNotHeadsUpWhenDozing_notDozing() {
+ // GIVEN state for "heads up when dozing" is true
ensureStateForHeadsUpWhenDozing();
+
+ // WHEN we're not dozing (in ambient display or sleeping)
when(mStatusBarStateController.isDozing()).thenReturn(false);
+ // THEN this entry shouldn't HUN
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
@@ -290,7 +262,7 @@
* {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_AMBIENT}.
*/
@Test
- public void testShouldHeadsUpWhenDozing_false_suppressingAmbient() {
+ public void testShouldNotHeadsUpWhenDozing_suppressingAmbient() {
ensureStateForHeadsUpWhenDozing();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
@@ -301,23 +273,18 @@
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't
- * get to pulse.
- */
@Test
- public void testShouldHeadsUpWhenDozing_false_lessImportant() {
+ public void testShouldNotHeadsUpWhenDozing_lessImportant() {
ensureStateForHeadsUpWhenDozing();
+ // Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't
+ // get to pulse
NotificationEntry entry = createNotification(IMPORTANCE_LOW);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * Heads up can happen.
- */
@Test
- public void testShouldHeadsUp_true() throws RemoteException {
+ public void testShouldHeadsUp() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -325,38 +292,11 @@
}
/**
- * Heads up notifications can be disabled in general.
- */
- @Test
- public void testShouldHeadsUp_false_noHunsAllowed() throws RemoteException {
- ensureStateForHeadsUpWhenAwake();
-
- // Set alerts disabled, this should cause heads up to be false
- mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
- assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse();
-
- NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
- }
-
- /**
- * If the device is dozing, we don't show as heads up.
- */
- @Test
- public void testShouldHeadsUp_false_dozing() throws RemoteException {
- ensureStateForHeadsUpWhenAwake();
- when(mStatusBarStateController.isDozing()).thenReturn(true);
-
- NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
- }
-
- /**
* If the notification is a bubble, and the user is not on AOD / lockscreen, then
* the bubble is shown rather than the heads up.
*/
@Test
- public void testShouldHeadsUp_false_bubble() throws RemoteException {
+ public void testShouldNotHeadsUp_bubble() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
// Bubble bit only applies to interruption when we're in the shade
@@ -369,7 +309,7 @@
* If we're not allowed to alert in general, we shouldn't be shown as heads up.
*/
@Test
- public void testShouldHeadsUp_false_alertCommonFalse() throws RemoteException {
+ public void testShouldNotHeadsUp_filtered() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
// Make canAlertCommon false by saying it's filtered out
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
@@ -383,7 +323,7 @@
* {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_PEEK}.
*/
@Test
- public void testShouldHeadsUp_false_suppressPeek() throws RemoteException {
+ public void testShouldNotHeadsUp_suppressPeek() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -399,7 +339,7 @@
* to show as a heads up.
*/
@Test
- public void testShouldHeadsUp_false_lessImportant() throws RemoteException {
+ public void testShouldNotHeadsUp_lessImportant() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
@@ -410,7 +350,7 @@
* If the device is not in use then we shouldn't be shown as heads up.
*/
@Test
- public void testShouldHeadsUp_false_deviceNotInUse() throws RemoteException {
+ public void testShouldNotHeadsUp_deviceNotInUse() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -424,61 +364,58 @@
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * If something wants to suppress this heads up, then it shouldn't be shown as a heads up.
- */
@Test
- public void testShouldHeadsUp_false_suppressed() throws RemoteException {
+ public void testShouldNotHeadsUp_headsUpSuppressed() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(false);
+
+ // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up.
+ mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeHeadsUp);
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
- verify(mHeadsUpSuppressor).canHeadsUp(any(), any());
}
- /**
- * On screen alerts don't happen when the device is in VR Mode.
- */
@Test
- public void testCanAlertAwakeCommon__false_vrMode() {
- ensureStateForAlertAwakeCommon();
- when(mPresenter.isDeviceInVrMode()).thenReturn(true);
+ public void testShouldNotHeadsUpAwake_awakeInterruptsSuppressed() throws RemoteException {
+ ensureStateForHeadsUpWhenAwake();
- NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
- assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
+ // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up.
+ mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeInterruptions);
+
+ NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
/**
* On screen alerts don't happen when the notification is snoozed.
*/
@Test
- public void testCanAlertAwakeCommon_false_snoozedPackage() {
- ensureStateForAlertAwakeCommon();
- when(mHeadsUpManager.isSnoozed(any())).thenReturn(true);
-
+ public void testShouldNotHeadsUp_snoozedPackage() {
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
- assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
+ ensureStateForAlertAwakeCommon();
+
+ when(mHeadsUpManager.isSnoozed(entry.getSbn().getPackageName())).thenReturn(true);
+
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * On screen alerts don't happen when that package has just launched fullscreen.
- */
+
@Test
- public void testCanAlertAwakeCommon_false_justLaunchedFullscreen() {
+ public void testShouldNotHeadsUp_justLaunchedFullscreen() {
ensureStateForAlertAwakeCommon();
+ // On screen alerts don't happen when that package has just launched fullscreen.
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
entry.notifyFullScreenIntentLaunched();
- assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
/**
* Bubbles can happen.
*/
@Test
- public void testShouldBubbleUp_true() {
+ public void testShouldBubbleUp() {
ensureStateForBubbleUp();
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isTrue();
}
@@ -487,7 +424,7 @@
* If the notification doesn't have permission to bubble, it shouldn't bubble.
*/
@Test
- public void shouldBubbleUp_false_notAllowedToBubble() {
+ public void shouldNotBubbleUp_notAllowedToBubble() {
ensureStateForBubbleUp();
NotificationEntry entry = createBubble();
@@ -502,7 +439,7 @@
* If the notification isn't a bubble, it should definitely not show as a bubble.
*/
@Test
- public void shouldBubbleUp_false_notABubble() {
+ public void shouldNotBubbleUp_notABubble() {
ensureStateForBubbleUp();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -517,7 +454,7 @@
* If the notification doesn't have bubble metadata, it shouldn't bubble.
*/
@Test
- public void shouldBubbleUp_false_invalidMetadata() {
+ public void shouldNotBubbleUp_invalidMetadata() {
ensureStateForBubbleUp();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -529,24 +466,18 @@
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(entry)).isFalse();
}
- /**
- * If the notification can't heads up in general, it shouldn't bubble.
- */
@Test
- public void shouldBubbleUp_false_alertAwakeCommonFalse() {
+ public void shouldNotBubbleUp_suppressedInterruptions() {
ensureStateForBubbleUp();
- // Make alert common return false by pretending we're in VR mode
- when(mPresenter.isDeviceInVrMode()).thenReturn(true);
+ // If the notification can't heads up in general, it shouldn't bubble.
+ mNotifInterruptionStateProvider.addSuppressor(mSuppressInterruptions);
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isFalse();
}
- /**
- * If the notification can't heads up in general, it shouldn't bubble.
- */
@Test
- public void shouldBubbleUp_false_alertCommonFalse() {
+ public void shouldNotBubbleUp_filteredOut() {
ensureStateForBubbleUp();
// Make canAlertCommon false by saying it's filtered out
@@ -592,20 +523,45 @@
.build();
}
- /**
- * Testable class overriding constructor.
- */
- public static class TestableNotificationInterruptionStateProvider extends
- NotificationInterruptionStateProvider {
-
- TestableNotificationInterruptionStateProvider(Context context,
- PowerManager powerManager, IDreamManager dreamManager,
- AmbientDisplayConfiguration ambientDisplayConfiguration,
- NotificationFilter notificationFilter,
- StatusBarStateController statusBarStateController,
- BatteryController batteryController) {
- super(context, powerManager, dreamManager, ambientDisplayConfiguration,
- notificationFilter, batteryController, statusBarStateController);
+ private final NotificationInterruptSuppressor
+ mSuppressAwakeHeadsUp =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return "suppressAwakeHeadsUp";
}
- }
+
+ @Override
+ public boolean suppressAwakeHeadsUp(NotificationEntry entry) {
+ return true;
+ }
+ };
+
+ private final NotificationInterruptSuppressor
+ mSuppressAwakeInterruptions =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return "suppressAwakeInterruptions";
+ }
+
+ @Override
+ public boolean suppressAwakeInterruptions(NotificationEntry entry) {
+ return true;
+ }
+ };
+
+ private final NotificationInterruptSuppressor
+ mSuppressInterruptions =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return "suppressInterruptions";
+ }
+
+ @Override
+ public boolean suppressInterruptions(NotificationEntry entry) {
+ return true;
+ }
+ };
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index d826ce1..d39b2c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -16,7 +16,10 @@
package com.android.systemui.statusbar.notification.logging;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -34,6 +37,7 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.InstanceId;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
@@ -43,6 +47,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -81,9 +86,10 @@
private NotificationEntry mEntry;
private TestableNotificationLogger mLogger;
- private NotificationEntryListener mNotificationEntryListener;
private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
+ private NotificationPanelLoggerFake mNotificationPanelLoggerFake =
+ new NotificationPanelLoggerFake();
@Before
public void setUp() {
@@ -97,6 +103,7 @@
.setUid(TEST_UID)
.setNotification(new Notification())
.setUser(UserHandle.CURRENT)
+ .setInstanceId(InstanceId.fakeInstanceId(1))
.build();
mEntry.setRow(mRow);
@@ -105,7 +112,6 @@
mExpansionStateLogger);
mLogger.setUpWithContainer(mListContainer);
verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
- mNotificationEntryListener = mEntryListenerCaptor.getValue();
}
@Test
@@ -164,6 +170,41 @@
verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
}
+ @Test
+ public void testLogPanelShownOnLoggingStart() {
+ when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
+ mLogger.startNotificationLogging();
+ assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+ assertEquals(false, mNotificationPanelLoggerFake.get(0).isLockscreen);
+ assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+ Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+ assertEquals(TEST_PACKAGE_NAME, n.packageName);
+ assertEquals(TEST_UID, n.uid);
+ assertEquals(1, n.instanceId);
+ assertEquals(false, n.isGroupSummary);
+ assertEquals(1 + BUCKET_ALERTING, n.section);
+ }
+
+ @Test
+ public void testLogPanelShownHandlesNullInstanceIds() {
+ // Construct a NotificationEntry like mEntry, but with a null instance id.
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setNotification(new Notification())
+ .setUser(UserHandle.CURRENT)
+ .build();
+ entry.setRow(mRow);
+
+ when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
+ mLogger.startNotificationLogging();
+ assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+ assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+ Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+ assertEquals(0, n.instanceId);
+ }
+
private class TestableNotificationLogger extends NotificationLogger {
TestableNotificationLogger(NotificationListener notificationListener,
@@ -173,7 +214,7 @@
IStatusBarService barService,
ExpansionStateLogger expansionStateLogger) {
super(notificationListener, uiBgExecutor, entryManager, statusBarStateController,
- expansionStateLogger);
+ expansionStateLogger, mNotificationPanelLoggerFake);
mBarService = barService;
// Make this on the current thread so we can wait for it during tests.
mHandler = Handler.createAsync(Looper.myLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
new file mode 100644
index 0000000..7e97629
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
@@ -0,0 +1,51 @@
+/*
+ * 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.systemui.statusbar.notification.logging;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NotificationPanelLoggerFake implements NotificationPanelLogger {
+ private List<CallRecord> mCalls = new ArrayList<>();
+
+ List<CallRecord> getCalls() {
+ return mCalls;
+ }
+
+ CallRecord get(int index) {
+ return mCalls.get(index);
+ }
+
+ @Override
+ public void logPanelShown(boolean isLockscreen,
+ List<NotificationEntry> visibleNotifications) {
+ mCalls.add(new CallRecord(isLockscreen,
+ NotificationPanelLogger.toNotificationProto(visibleNotifications)));
+ }
+
+ public static class CallRecord {
+ public boolean isLockscreen;
+ public Notifications.NotificationList list;
+ CallRecord(boolean isLockscreen, Notifications.NotificationList list) {
+ this.isLockscreen = isLockscreen;
+ this.list = list;
+ }
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 5d0349d..a21a047 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -56,12 +56,12 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -108,7 +108,7 @@
@Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
@Mock private HeadsUpManager mHeadsUpManager;
- @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ @Mock private NotificationInterruptStateProvider mNotificationInterruptionStateProvider;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationGutsManager mGutsManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
new file mode 100644
index 0000000..291c039
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class KeyguardIndicationTextViewTest extends SysuiTestCase {
+
+ private KeyguardIndicationTextView mKeyguardIndicationTextView;
+
+ @Before
+ public void setup() {
+ mKeyguardIndicationTextView = new KeyguardIndicationTextView(mContext);
+ }
+
+ @Test
+ public void switchIndication_null_hideIndication() {
+ mKeyguardIndicationTextView.switchIndication(null /* text */);
+
+ assertThat(mKeyguardIndicationTextView.getVisibility()).isEqualTo(View.INVISIBLE);
+ assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("");
+ }
+
+ @Test
+ public void switchIndication_emptyText_hideIndication() {
+ mKeyguardIndicationTextView.switchIndication("" /* text */);
+
+ assertThat(mKeyguardIndicationTextView.getVisibility()).isEqualTo(View.INVISIBLE);
+ assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("");
+ }
+
+ @Test
+ public void switchIndication_newText_updateProperly() {
+ mKeyguardIndicationTextView.switchIndication("test_indication" /* text */);
+
+ assertThat(mKeyguardIndicationTextView.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("test_indication");
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index c5b6969..cc2d1c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -37,7 +37,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShadeWindowBlurController;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -81,7 +81,7 @@
@Mock private DockManager mDockManager;
@Mock private NotificationPanelViewController mNotificationPanelViewController;
@Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
- @Mock private NotificationShadeWindowBlurController mNotificationShadeWindowBlurController;
+ @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
@Mock private SuperStatusBarViewFactory mStatusBarViewFactory;
@Before
@@ -116,7 +116,7 @@
new CommandQueue(mContext),
mShadeController,
mDockManager,
- mNotificationShadeWindowBlurController,
+ mNotificationShadeDepthController,
mView,
mNotificationPanelViewController,
mStatusBarViewFactory);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 1e4df27..b9c5b7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -67,10 +67,10 @@
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -183,7 +183,7 @@
mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class),
mock(NotificationLockscreenUserManager.class),
mKeyguardStateController,
- mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class),
+ mock(NotificationInterruptStateProvider.class), mock(MetricsLogger.class),
mock(LockPatternUtils.class), mHandler, mHandler, mUiBgExecutor,
mActivityIntentHelper, mBubbleController, mShadeController, mFeatureFlags,
mNotifPipeline, mNotifCollection)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index b9d2d22..318e9b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -16,8 +16,9 @@
import static android.view.Display.DEFAULT_DISPLAY;
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
@@ -35,6 +36,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -48,12 +50,12 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -62,6 +64,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
@@ -72,6 +75,9 @@
private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
+ private NotificationInterruptStateProvider mNotificationInterruptStateProvider =
+ mock(NotificationInterruptStateProvider.class);
+ private NotificationInterruptSuppressor mInterruptSuppressor;
private CommandQueue mCommandQueue;
private FakeMetricsLogger mMetricsLogger;
private ShadeController mShadeController = mock(ShadeController.class);
@@ -95,11 +101,11 @@
mDependency.injectMockDependency(NotificationViewHierarchyManager.class);
mDependency.injectMockDependency(NotificationRemoteInputManager.Callback.class);
mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
- mDependency.injectMockDependency(NotificationInterruptionStateProvider.class);
mDependency.injectMockDependency(NotificationMediaManager.class);
mDependency.injectMockDependency(VisualStabilityManager.class);
mDependency.injectMockDependency(NotificationGutsManager.class);
mDependency.injectMockDependency(NotificationShadeWindowController.class);
+ mDependency.injectMockDependency(ForegroundServiceNotificationListener.class);
NotificationEntryManager entryManager =
mDependency.injectMockDependency(NotificationEntryManager.class);
when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
@@ -107,18 +113,25 @@
NotificationShadeWindowView notificationShadeWindowView =
mock(NotificationShadeWindowView.class);
when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources());
+
mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext,
mock(NotificationPanelViewController.class), mock(HeadsUpManagerPhone.class),
notificationShadeWindowView, mock(NotificationListContainerViewGroup.class),
mock(DozeScrimController.class), mock(ScrimController.class),
mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
- mock(NotificationAlertingManager.class), mock(KeyguardStateController.class),
+ mock(KeyguardStateController.class),
mock(KeyguardIndicationController.class), mStatusBar,
- mock(ShadeControllerImpl.class), mCommandQueue, mInitController);
+ mock(ShadeControllerImpl.class), mCommandQueue, mInitController,
+ mNotificationInterruptStateProvider);
+ mInitController.executePostInitTasks();
+ ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor =
+ ArgumentCaptor.forClass(NotificationInterruptSuppressor.class);
+ verify(mNotificationInterruptStateProvider).addSuppressor(suppressorCaptor.capture());
+ mInterruptSuppressor = suppressorCaptor.getValue();
}
@Test
- public void testHeadsUp_disabledStatusBar() {
+ public void testSuppressHeadsUp_disabledStatusBar() {
Notification n = new Notification.Builder(getContext(), "a").build();
NotificationEntry entry = new NotificationEntryBuilder()
.setPkg("a")
@@ -130,12 +143,12 @@
false /* animate */);
TestableLooper.get(this).processAllMessages();
- assertFalse("The panel shouldn't allow heads up while disabled",
- mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
+ assertTrue("The panel should suppress heads up while disabled",
+ mInterruptSuppressor.suppressAwakeHeadsUp(entry));
}
@Test
- public void testHeadsUp_disabledNotificationShade() {
+ public void testSuppressHeadsUp_disabledNotificationShade() {
Notification n = new Notification.Builder(getContext(), "a").build();
NotificationEntry entry = new NotificationEntryBuilder()
.setPkg("a")
@@ -147,8 +160,39 @@
false /* animate */);
TestableLooper.get(this).processAllMessages();
- assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled",
- mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
+ assertTrue("The panel should suppress interruptions while notification shade "
+ + "disabled",
+ mInterruptSuppressor.suppressAwakeHeadsUp(entry));
+ }
+
+ @Test
+ public void testSuppressInterruptions_vrMode() {
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg("a")
+ .setOpPkg("a")
+ .setTag("a")
+ .setNotification(n)
+ .build();
+ mStatusBarNotificationPresenter.mVrMode = true;
+
+ assertTrue("Vr mode should suppress interruptions",
+ mInterruptSuppressor.suppressAwakeInterruptions(entry));
+ }
+
+ @Test
+ public void testSuppressInterruptions_statusBarAlertsDisabled() {
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg("a")
+ .setOpPkg("a")
+ .setTag("a")
+ .setNotification(n)
+ .build();
+ when(mStatusBar.areNotificationAlertsDisabled()).thenReturn(true);
+
+ assertTrue("StatusBar alerts disabled shouldn't allow interruptions",
+ mInterruptSuppressor.suppressInterruptions(entry));
}
@Test
@@ -172,4 +216,3 @@
}
}
}
-
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 0d7734e..679ac22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -42,7 +42,7 @@
import android.app.StatusBarManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
-import android.content.Context;
+import android.content.ContentResolver;
import android.content.IntentFilter;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
@@ -109,19 +109,20 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
@@ -129,6 +130,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
@@ -160,7 +162,7 @@
private StatusBar mStatusBar;
private FakeMetricsLogger mMetricsLogger;
private PowerManager mPowerManager;
- private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private TestableNotificationInterruptStateProviderImpl mNotificationInterruptStateProvider;
@Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
@@ -178,7 +180,6 @@
@Mock private DozeScrimController mDozeScrimController;
@Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@Mock private BiometricUnlockController mBiometricUnlockController;
- @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
@Mock private VisualStabilityManager mVisualStabilityManager;
@Mock private NotificationListener mNotificationListener;
@Mock private KeyguardViewMediator mKeyguardViewMediator;
@@ -192,9 +193,9 @@
@Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationFilter mNotificationFilter;
@Mock private NotificationAlertingManager mNotificationAlertingManager;
+ @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
@Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
@Mock private NotificationShadeWindowView mNotificationShadeWindowView;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private AssistManager mAssistManager;
@@ -262,10 +263,12 @@
mPowerManager = new PowerManager(mContext, powerManagerService, thermalService,
Handler.createAsync(Looper.myLooper()));
- mNotificationInterruptionStateProvider =
- new TestableNotificationInterruptionStateProvider(mContext, mPowerManager,
+ mNotificationInterruptStateProvider =
+ new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
+ mPowerManager,
mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
- mStatusBarStateController, mBatteryController);
+ mStatusBarStateController, mBatteryController, mHeadsUpManager,
+ new Handler(TestableLooper.get(this).getLooper()));
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -273,7 +276,7 @@
mMetricsLogger = new FakeMetricsLogger();
NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener,
mUiBgExecutor, mock(NotificationEntryManager.class), mStatusBarStateController,
- mExpansionStateLogger);
+ mExpansionStateLogger, new NotificationPanelLoggerFake());
notificationLogger.setVisibilityReporter(mock(Runnable.class));
when(mCommandQueue.asBinder()).thenReturn(new Binder());
@@ -298,9 +301,6 @@
return null;
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
- mNotificationInterruptionStateProvider.setUpWithPresenter(mNotificationPresenter,
- mHeadsUpManager, mHeadsUpSuppressor);
-
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle();
@@ -347,7 +347,7 @@
),
mNotificationGutsManager,
notificationLogger,
- mNotificationInterruptionStateProvider,
+ mNotificationInterruptStateProvider,
mNotificationViewHierarchyManager,
mKeyguardViewMediator,
mNotificationAlertingManager,
@@ -561,7 +561,6 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a")
.setGroup("a")
@@ -577,7 +576,7 @@
.setImportance(IMPORTANCE_HIGH)
.build();
- assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+ assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -586,7 +585,6 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a")
.setGroup("a")
@@ -602,7 +600,7 @@
.setImportance(IMPORTANCE_HIGH)
.build();
- assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+ assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -611,7 +609,6 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a").build();
@@ -624,7 +621,7 @@
.setSuppressedVisualEffects(SUPPRESSED_EFFECT_PEEK)
.build();
- assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+ assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -633,7 +630,6 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a").build();
@@ -645,7 +641,7 @@
.setImportance(IMPORTANCE_HIGH)
.build();
- assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+ assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -871,19 +867,21 @@
verify(mDozeServiceHost).setDozeSuppressed(false);
}
- public static class TestableNotificationInterruptionStateProvider extends
- NotificationInterruptionStateProvider {
+ public static class TestableNotificationInterruptStateProviderImpl extends
+ NotificationInterruptStateProviderImpl {
- TestableNotificationInterruptionStateProvider(
- Context context,
+ TestableNotificationInterruptStateProviderImpl(
+ ContentResolver contentResolver,
PowerManager powerManager,
IDreamManager dreamManager,
AmbientDisplayConfiguration ambientDisplayConfiguration,
NotificationFilter filter,
StatusBarStateController controller,
- BatteryController batteryController) {
- super(context, powerManager, dreamManager, ambientDisplayConfiguration, filter,
- batteryController, controller);
+ BatteryController batteryController,
+ HeadsUpManager headsUpManager,
+ Handler mainHandler) {
+ super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter,
+ batteryController, controller, headsUpManager, mainHandler);
mUseHeadsUp = true;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index a0d551c..831925f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -235,7 +235,7 @@
subs.add(subscription);
}
when(mMockSm.getActiveSubscriptionInfoList()).thenReturn(subs);
- when(mMockSm.getActiveAndHiddenSubscriptionInfoList()).thenReturn(subs);
+ when(mMockSm.getCompleteActiveSubscriptionInfoList()).thenReturn(subs);
mNetworkController.doUpdateMobileControllers();
}
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 5b73dd5..2fbba68 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -62,26 +62,14 @@
apex_available: ["com.android.tethering"],
}
-droidstubs {
- name: "framework-tethering-stubs-sources",
- defaults: ["framework-module-stubs-defaults-module_libs_api"],
+stubs_defaults {
+ name: "framework-tethering-stubs-defaults",
srcs: [
"src/android/net/TetheredClient.java",
"src/android/net/TetheringManager.java",
"src/android/net/TetheringConstants.java",
],
- libs: [
- "tethering-aidl-interfaces-java",
- "framework-all",
- ],
- sdk_version: "core_platform",
-}
-
-java_library {
- name: "framework-tethering-stubs",
- srcs: [":framework-tethering-stubs-sources"],
- libs: ["framework-all"],
- sdk_version: "core_platform",
+ libs: ["tethering-aidl-interfaces-java"],
}
filegroup {
@@ -101,3 +89,53 @@
],
path: "src"
}
+
+droidstubs {
+ name: "framework-tethering-stubs-srcs-publicapi",
+ defaults: [
+ "framework-module-stubs-defaults-publicapi",
+ "framework-tethering-stubs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-tethering-stubs-srcs-systemapi",
+ defaults: [
+ "framework-module-stubs-defaults-systemapi",
+ "framework-tethering-stubs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-tethering-api-module_libs_api",
+ defaults: [
+ "framework-module-api-defaults-module_libs_api",
+ "framework-tethering-stubs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-tethering-stubs-srcs-module_libs_api",
+ defaults: [
+ "framework-module-stubs-defaults-module_libs_api",
+ "framework-tethering-stubs-defaults",
+ ],
+}
+
+java_library {
+ name: "framework-tethering-stubs-publicapi",
+ srcs: [":framework-tethering-stubs-srcs-publicapi"],
+ sdk_version: "current",
+}
+
+java_library {
+ name: "framework-tethering-stubs-systemapi",
+ srcs: [":framework-tethering-stubs-srcs-systemapi"],
+ sdk_version: "system_current",
+}
+
+java_library {
+ name: "framework-tethering-stubs-module_libs_api",
+ srcs: [":framework-tethering-stubs-srcs-module_libs_api"],
+ sdk_version: "module_current",
+}
diff --git a/services/Android.bp b/services/Android.bp
index ef47867..c4be003 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -78,7 +78,7 @@
libs: [
"android.hidl.manager-V1.0-java",
- "framework-tethering-stubs",
+ "framework-tethering-stubs-module_libs_api",
],
plugins: [
diff --git a/services/api/current.txt b/services/api/current.txt
index 8c90165..9bbb3ef 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -3,9 +3,9 @@
public interface RuntimePermissionsPersistence {
method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
- method public void deleteAsUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.permission.persistence.RuntimePermissionsState readAsUser(@NonNull android.os.UserHandle);
- method public void writeAsUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
+ method public void deleteForUser(@NonNull android.os.UserHandle);
+ method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
+ method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
}
public final class RuntimePermissionsState {
@@ -17,7 +17,7 @@
field public static final int NO_VERSION = -1; // 0xffffffff
}
- public static class RuntimePermissionsState.PermissionState {
+ public static final class RuntimePermissionsState.PermissionState {
ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
method public int getFlags();
method @NonNull public String getName();
@@ -30,9 +30,9 @@
public interface RolesPersistence {
method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
- method public void deleteAsUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.role.persistence.RolesState readAsUser(@NonNull android.os.UserHandle);
- method public void writeAsUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
+ method public void deleteForUser(@NonNull android.os.UserHandle);
+ method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
+ method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
}
public final class RolesState {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5619478..8265009 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -18,6 +18,7 @@
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
@@ -624,7 +625,7 @@
+ ", flags=" + flags + ")");
}
mForAugmentedAutofillOnly = true;
- triggerAugmentedAutofillLocked();
+ triggerAugmentedAutofillLocked(flags);
return;
}
@@ -834,7 +835,7 @@
}
// Although "standard" autofill is disabled, it might still trigger augmented autofill
- if (triggerAugmentedAutofillLocked() != null) {
+ if (triggerAugmentedAutofillLocked(requestFlags) != null) {
mForAugmentedAutofillOnly = true;
if (sDebug) {
Slog.d(TAG, "Service disabled autofill for " + mComponentName
@@ -2465,7 +2466,7 @@
// triggered augmented autofill
if (!isSameViewEntered) {
if (sDebug) Slog.d(TAG, "trigger augmented autofill.");
- triggerAugmentedAutofillLocked();
+ triggerAugmentedAutofillLocked(flags);
} else {
if (sDebug) Slog.d(TAG, "skip augmented autofill for same view.");
}
@@ -2681,7 +2682,7 @@
response, filterText, response.getInlineActions(), mCurrentViewId,
this, () -> {
synchronized (mLock) {
- requestHideFillUi(mCurrentViewId);
+ mInlineSuggestionSession.hideInlineSuggestionsUi(mCurrentViewId);
}
}, remoteRenderService);
if (inlineSuggestionsResponse == null) {
@@ -2863,8 +2864,8 @@
// The default autofill service cannot fullfill the request, let's check if the augmented
// autofill service can.
- mAugmentedAutofillDestroyer = triggerAugmentedAutofillLocked();
- if (mAugmentedAutofillDestroyer == null) {
+ mAugmentedAutofillDestroyer = triggerAugmentedAutofillLocked(flags);
+ if (mAugmentedAutofillDestroyer == null && ((flags & FLAG_PASSWORD_INPUT_TYPE) == 0)) {
if (sVerbose) {
Slog.v(TAG, "canceling session " + id + " when service returned null and it cannot "
+ "be augmented. AutofillableIds: " + autofillableIds);
@@ -2874,8 +2875,14 @@
removeSelf();
} else {
if (sVerbose) {
- Slog.v(TAG, "keeping session " + id + " when service returned null but "
- + "it can be augmented. AutofillableIds: " + autofillableIds);
+ if ((flags & FLAG_PASSWORD_INPUT_TYPE) != 0) {
+ Slog.v(TAG, "keeping session " + id + " when service returned null and "
+ + "augmented service is disabled for password fields. "
+ + "AutofillableIds: " + autofillableIds);
+ } else {
+ Slog.v(TAG, "keeping session " + id + " when service returned null but "
+ + "it can be augmented. AutofillableIds: " + autofillableIds);
+ }
}
mAugmentedAutofillableIds = autofillableIds;
try {
@@ -2894,7 +2901,12 @@
// TODO(b/123099468): might need to call it in other places, like when the service returns a
// non-null response but without datasets (for example, just SaveInfo)
@GuardedBy("mLock")
- private Runnable triggerAugmentedAutofillLocked() {
+ private Runnable triggerAugmentedAutofillLocked(int flags) {
+ // (TODO: b/141703197) Fix later by passing info to service.
+ if ((flags & FLAG_PASSWORD_INPUT_TYPE) != 0) {
+ return null;
+ }
+
// Check if Smart Suggestions is supported...
final @SmartSuggestionMode int supportedModes = mService
.getSupportedSmartSuggestionModesLocked();
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index 82e5003..ee59d89 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -167,8 +167,7 @@
inlineSuggestions.add(inlineSuggestion);
}
- // We should only add inline actions if there is at least one suggestion.
- if (!inlineSuggestions.isEmpty() && inlineActions != null) {
+ if (inlineActions != null) {
for (InlineAction inlineAction : inlineActions) {
final InlineSuggestion inlineActionSuggestion = createInlineAction(isAugmented,
mergedInlinePresentation(request, 0, inlineAction.getInlinePresentation()),
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4cc65900..942d563 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -99,7 +99,7 @@
"android.hardware.tv.cec-V1.0-java",
"android.hardware.vibrator-java",
"app-compat-annotations",
- "framework-tethering-stubs",
+ "framework-tethering-stubs-module_libs_api",
"ike-stubs",
],
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 7840b19..9b04e79 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1672,7 +1672,7 @@
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- intent.putExtra("time-zone", zone.getID());
+ intent.putExtra(Intent.EXTRA_TIMEZONE, zone.getID());
getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
}
}
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index b43ae36..cfb79aa 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -100,7 +100,7 @@
@Nullable public final ComponentName component;
@UserIdInt public final int userId;
- private ServiceInfo(ResolveInfo resolveInfo, int currentUserId) {
+ ServiceInfo(ResolveInfo resolveInfo, int currentUserId) {
Preconditions.checkArgument(resolveInfo.serviceInfo.getComponentName() != null);
Bundle metadata = resolveInfo.serviceInfo.metaData;
@@ -316,6 +316,7 @@
}
mContext.unbindService(this);
+ onServiceDisconnected(mServiceInfo.component);
mServiceInfo = ServiceInfo.NONE;
}
@@ -339,15 +340,13 @@
@Override
public final void onServiceConnected(ComponentName component, IBinder binder) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ Preconditions.checkState(mBinder == null);
if (D) {
Log.i(TAG, getLogPrefix() + " connected to " + component.toShortString());
}
mBinder = binder;
-
- // we always run the on bind callback even if we know that the binder is dead already so
- // that there are always balance pairs of bind/unbind callbacks
if (mOnBind != null) {
try {
mOnBind.run(binder);
@@ -357,19 +356,16 @@
Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
}
}
-
- try {
- // setting the binder to null lets us skip queued transactions
- binder.linkToDeath(() -> mBinder = null, 0);
- } catch (RemoteException e) {
- mBinder = null;
- }
}
@Override
public final void onServiceDisconnected(ComponentName component) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ if (mBinder == null) {
+ return;
+ }
+
if (D) {
Log.i(TAG, getLogPrefix() + " disconnected from " + component.toShortString());
}
@@ -391,18 +387,18 @@
onBestServiceChanged(true);
}
- private void onUserSwitched(@UserIdInt int userId) {
+ void onUserSwitched(@UserIdInt int userId) {
mCurrentUserId = userId;
onBestServiceChanged(false);
}
- private void onUserUnlocked(@UserIdInt int userId) {
+ void onUserUnlocked(@UserIdInt int userId) {
if (userId == mCurrentUserId) {
onBestServiceChanged(false);
}
}
- private void onPackageChanged(String packageName) {
+ void onPackageChanged(String packageName) {
// force a rebind if the changed package was the currently connected package
String currentPackageName =
mServiceInfo.component != null ? mServiceInfo.component.getPackageName() : null;
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 7c833fa..eace86b 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -75,7 +75,9 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -293,7 +295,7 @@
public void onChange(boolean selfChange, Uri uri) {
synchronized (mLock) {
// setup wizard is done now so we can unblock
- if (setupWizardCompleteForCurrentUser()) {
+ if (setupWizardCompleteForCurrentUser() && !selfChange) {
mSetupWizardComplete = true;
getContext().getContentResolver()
.unregisterContentObserver(mSetupWizardObserver);
@@ -348,6 +350,9 @@
IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(mBatteryReceiver, batteryFilter);
+ context.registerReceiver(mSettingsRestored,
+ new IntentFilter(Intent.ACTION_SETTING_RESTORED), null, mHandler);
+
mLocalPowerManager =
LocalServices.getService(PowerManagerInternal.class);
initPowerSave();
@@ -395,6 +400,22 @@
mHandler.post(() -> updateSystemProperties());
}
+ private final BroadcastReceiver mSettingsRestored = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ List<String> settings = Arrays.asList(
+ Secure.UI_NIGHT_MODE, Secure.DARK_THEME_CUSTOM_START_TIME,
+ Secure.DARK_THEME_CUSTOM_END_TIME);
+ if (settings.contains(intent.getExtras().getCharSequence(Intent.EXTRA_SETTING_NAME))) {
+ synchronized (mLock) {
+ updateNightModeFromSettingsLocked(context, context.getResources(),
+ UserHandle.getCallingUserId());
+ updateConfigurationLocked();
+ }
+ }
+ }
+ };
+
private void initPowerSave() {
mPowerSave =
mLocalPowerManager.getLowPowerState(ServiceType.NIGHT_MODE)
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 59f64ac..8f5fbf7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2931,25 +2931,35 @@
final PlatformCompat platformCompat = (PlatformCompat)
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
String toggleValue = getNextArgRequired();
- if (toggleValue.equals("reset-all")) {
- final String packageName = getNextArgRequired();
- pw.println("Reset all changes for " + packageName + " to default value.");
- platformCompat.clearOverrides(packageName);
- return 0;
- }
- long changeId;
- String changeIdString = getNextArgRequired();
- try {
- changeId = Long.parseLong(changeIdString);
- } catch (NumberFormatException e) {
- changeId = platformCompat.lookupChangeId(changeIdString);
- }
- if (changeId == -1) {
- pw.println("Unknown or invalid change: '" + changeIdString + "'.");
- return -1;
+ boolean toggleAll = false;
+ int targetSdkVersion = -1;
+ long changeId = -1;
+
+ if (toggleValue.endsWith("-all")) {
+ toggleValue = toggleValue.substring(0, toggleValue.lastIndexOf("-all"));
+ toggleAll = true;
+ if (!toggleValue.equals("reset")) {
+ try {
+ targetSdkVersion = Integer.parseInt(getNextArgRequired());
+ } catch (NumberFormatException e) {
+ pw.println("Invalid targetSdkVersion!");
+ return -1;
+ }
+ }
+ } else {
+ String changeIdString = getNextArgRequired();
+ try {
+ changeId = Long.parseLong(changeIdString);
+ } catch (NumberFormatException e) {
+ changeId = platformCompat.lookupChangeId(changeIdString);
+ }
+ if (changeId == -1) {
+ pw.println("Unknown or invalid change: '" + changeIdString + "'.");
+ return -1;
+ }
}
String packageName = getNextArgRequired();
- if (!platformCompat.isKnownChangeId(changeId)) {
+ if (!toggleAll && !platformCompat.isKnownChangeId(changeId)) {
pw.println("Warning! Change " + changeId + " is not known yet. Enabling/disabling it"
+ " could have no effect.");
}
@@ -2958,22 +2968,49 @@
try {
switch (toggleValue) {
case "enable":
- enabled.add(changeId);
- CompatibilityChangeConfig overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- pw.println("Enabled change " + changeId + " for " + packageName + ".");
+ if (toggleAll) {
+ int numChanges = platformCompat.enableTargetSdkChanges(packageName,
+ targetSdkVersion);
+ if (numChanges == 0) {
+ pw.println("No changes were enabled.");
+ return -1;
+ }
+ pw.println("Enabled " + numChanges + " changes gated by targetSdkVersion "
+ + targetSdkVersion + " for " + packageName + ".");
+ } else {
+ enabled.add(changeId);
+ CompatibilityChangeConfig overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Enabled change " + changeId + " for " + packageName + ".");
+ }
return 0;
case "disable":
- disabled.add(changeId);
- overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- pw.println("Disabled change " + changeId + " for " + packageName + ".");
+ if (toggleAll) {
+ int numChanges = platformCompat.disableTargetSdkChanges(packageName,
+ targetSdkVersion);
+ if (numChanges == 0) {
+ pw.println("No changes were disabled.");
+ return -1;
+ }
+ pw.println("Disabled " + numChanges + " changes gated by targetSdkVersion "
+ + targetSdkVersion + " for " + packageName + ".");
+ } else {
+ disabled.add(changeId);
+ CompatibilityChangeConfig overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Disabled change " + changeId + " for " + packageName + ".");
+ }
return 0;
case "reset":
+ if (toggleAll) {
+ platformCompat.clearOverrides(packageName);
+ pw.println("Reset all changes for " + packageName + " to default value.");
+ return 0;
+ }
if (platformCompat.clearOverride(changeId, packageName)) {
pw.println("Reset change " + changeId + " for " + packageName
+ " to default value.");
@@ -3304,6 +3341,8 @@
pw.println(" enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>.");
pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
+ pw.println(" enable-all|disable-all <targetSdkVersion> <PACKAGE_NAME");
+ pw.println(" Toggles all changes that are gated by <targetSdkVersion>.");
pw.println(" reset-all <PACKAGE_NAME>");
pw.println(" Removes all existing overrides for all changes for ");
pw.println(" <PACKAGE_NAME> (back to default behaviour).");
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 3a6065e..86d9028 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -121,6 +121,7 @@
static final int COMPACT_PROCESS_MSG = 1;
static final int COMPACT_SYSTEM_MSG = 2;
static final int SET_FROZEN_PROCESS_MSG = 3;
+ static final int REPORT_UNFREEZE_MSG = 4;
//TODO:change this static definition into a configurable flag.
static final int FREEZE_TIMEOUT_MS = 500;
@@ -613,30 +614,6 @@
FREEZE_TIMEOUT_MS);
}
- private final class UnfreezeStats {
- final int mPid;
- final String mName;
- final long mFrozenDuration;
-
- UnfreezeStats(int pid, String name, long frozenDuration) {
- mPid = pid;
- mName = name;
- mFrozenDuration = frozenDuration;
- }
-
- public int getPid() {
- return mPid;
- }
-
- public String getName() {
- return mName;
- }
-
- public long getFrozenDuration() {
- return mFrozenDuration;
- }
- }
-
@GuardedBy("mAm")
void unfreezeAppLocked(ProcessRecord app) {
mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
@@ -667,12 +644,11 @@
Slog.d(TAG_AM, "sync unfroze " + app.pid + " " + app.processName);
}
- UnfreezeStats stats = new UnfreezeStats(app.pid, app.processName,
- app.freezeUnfreezeTime - freezeTime);
-
mFreezeHandler.sendMessage(
- mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, REPORT_UNFREEZE, 0,
- stats));
+ mFreezeHandler.obtainMessage(REPORT_UNFREEZE_MSG,
+ app.pid,
+ (int) Math.min(app.freezeUnfreezeTime - freezeTime, Integer.MAX_VALUE),
+ app.processName));
}
}
@@ -945,14 +921,19 @@
@Override
public void handleMessage(Message msg) {
- if (msg.what != SET_FROZEN_PROCESS_MSG) {
- return;
- }
+ switch (msg.what) {
+ case SET_FROZEN_PROCESS_MSG:
+ freezeProcess((ProcessRecord) msg.obj);
+ break;
+ case REPORT_UNFREEZE_MSG:
+ int pid = msg.arg1;
+ int frozenDuration = msg.arg2;
+ String processName = (String) msg.obj;
- if (msg.arg1 == DO_FREEZE) {
- freezeProcess((ProcessRecord) msg.obj);
- } else if (msg.arg1 == REPORT_UNFREEZE) {
- reportUnfreeze((UnfreezeStats) msg.obj);
+ reportUnfreeze(pid, frozenDuration, processName);
+ break;
+ default:
+ return;
}
}
@@ -1015,18 +996,18 @@
}
}
- private void reportUnfreeze(UnfreezeStats stats) {
+ private void reportUnfreeze(int pid, int frozenDuration, String processName) {
- EventLog.writeEvent(EventLogTags.AM_UNFREEZE, stats.getPid(), stats.getName());
+ EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, processName);
// See above for why we're not taking mPhenotypeFlagLock here
if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
FrameworkStatsLog.write(
FrameworkStatsLog.APP_FREEZE_CHANGED,
FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__UNFREEZE_APP,
- stats.getPid(),
- stats.getName(),
- stats.getFrozenDuration());
+ pid,
+ processName,
+ frozenDuration);
}
}
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 91348aa..b584ea5 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1708,11 +1708,6 @@
// TOP process passes all capabilities to the service.
capability |= PROCESS_CAPABILITY_ALL;
}
- } else if (clientProcState
- <= PROCESS_STATE_FOREGROUND_SERVICE) {
- if (cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
- clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
- }
}
} else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
if (clientProcState <
@@ -2036,7 +2031,7 @@
case PROCESS_STATE_TOP:
return PROCESS_CAPABILITY_ALL;
case PROCESS_STATE_BOUND_TOP:
- return PROCESS_CAPABILITY_ALL_IMPLICIT;
+ return PROCESS_CAPABILITY_NONE;
case PROCESS_STATE_FOREGROUND_SERVICE:
if (app.hasForegroundServices()) {
// Capability from FGS are conditional depending on foreground service type in
@@ -2044,10 +2039,12 @@
return PROCESS_CAPABILITY_NONE;
} else {
// process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client.
+ // the implicit capability could be removed in the future, client should use
+ // BIND_INCLUDE_CAPABILITY flag.
return PROCESS_CAPABILITY_ALL_IMPLICIT;
}
case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
- return PROCESS_CAPABILITY_ALL_IMPLICIT;
+ return PROCESS_CAPABILITY_NONE;
default:
return PROCESS_CAPABILITY_NONE;
}
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 7774633..87e1dbc 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,7 +19,7 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static android.app.AppOpsManager.CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE;
+import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
import static android.app.AppOpsManager.FILTER_BY_FEATURE_ID;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
@@ -40,6 +40,7 @@
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OpEventProxyInfo;
+import static android.app.AppOpsManager.RestrictionBypass;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
@@ -55,6 +56,7 @@
import static android.app.AppOpsManager.extractUidStateFromKey;
import static android.app.AppOpsManager.makeKey;
import static android.app.AppOpsManager.modeToName;
+import static android.app.AppOpsManager.opAllowSystemBypassRestriction;
import static android.app.AppOpsManager.opToName;
import static android.app.AppOpsManager.opToPublicName;
import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
@@ -73,7 +75,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManager.HistoricalOps;
@@ -86,14 +87,11 @@
import android.app.AsyncNotedAppOp;
import android.app.RuntimeAppOpAccessMessage;
import android.app.SyncNotedAppOp;
-import android.compat.Compatibility;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
@@ -666,15 +664,19 @@
final static class Ops extends SparseArray<Op> {
final String packageName;
final UidState uidState;
- final boolean isPrivileged;
+
+ /**
+ * The restriction properties of the package. If {@code null} it could not have been read
+ * yet and has to be refreshed.
+ */
+ @Nullable RestrictionBypass bypass;
/** Lazily populated cache of featureIds of this package */
final @NonNull ArraySet<String> knownFeatureIds = new ArraySet<>();
- Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
+ Ops(String _packageName, UidState _uidState) {
packageName = _packageName;
uidState = _uidState;
- isPrivileged = _isPrivileged;
}
}
@@ -1519,7 +1521,11 @@
return;
}
+ // Reset cached package properties to re-initialize when needed
+ ops.bypass = null;
ops.knownFeatureIds.clear();
+
+ // Merge data collected for removed features into their successor features
int numOps = ops.size();
for (int opNum = 0; opNum < numOps; opNum++) {
Op op = ops.valueAt(opNum);
@@ -1953,8 +1959,7 @@
return Collections.emptyList();
}
synchronized (this) {
- Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false /* isPrivileged */,
- false /* edit */);
+ Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false /* edit */);
if (pkgOps == null) {
return null;
}
@@ -2087,8 +2092,7 @@
op.removeFeaturesWithNoTime();
if (op.mFeatures.size() == 0) {
- Ops ops = getOpsRawLocked(uid, packageName, null, false /* isPrivileged */,
- false /* edit */);
+ Ops ops = getOpsLocked(uid, packageName, null, null, false /* edit */);
if (ops != null) {
ops.remove(op.op);
if (ops.size() <= 0) {
@@ -2390,9 +2394,9 @@
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
- boolean isPrivileged;
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
+ bypass = verifyAndGetBypass(uid, packageName, null);
} catch (SecurityException e) {
Slog.e(TAG, "Cannot setMode", e);
return;
@@ -2400,7 +2404,7 @@
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
- Op op = getOpLocked(code, uid, packageName, null, isPrivileged, true);
+ Op op = getOpLocked(code, uid, packageName, null, bypass, true);
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
@@ -2674,10 +2678,8 @@
synchronized (this) {
int switchOp = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
- // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
int notifiedOps;
- if (Compatibility.isChangeEnabled(
- CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE)) {
+ if ((flags & CALL_BACK_ON_SWITCHED_OP) == 0) {
if (op == OP_NONE) {
notifiedOps = ALL_OPS;
} else {
@@ -2798,10 +2800,9 @@
*/
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
boolean raw) {
- boolean isPrivileged;
-
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
+ bypass = verifyAndGetBypass(uid, packageName, null);
} catch (SecurityException e) {
Slog.e(TAG, "checkOperation", e);
return AppOpsManager.opToDefaultMode(code);
@@ -2811,7 +2812,7 @@
return AppOpsManager.MODE_IGNORED;
}
synchronized (this) {
- if (isOpRestrictedLocked(uid, code, packageName, null, isPrivileged)) {
+ if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -2821,7 +2822,7 @@
final int rawMode = uidState.opModes.get(code);
return raw ? rawMode : uidState.evalMode(code, rawMode);
}
- Op op = getOpLocked(code, uid, packageName, null, false, false);
+ Op op = getOpLocked(code, uid, packageName, null, bypass, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -2884,7 +2885,7 @@
public int checkPackage(int uid, String packageName) {
Objects.requireNonNull(packageName);
try {
- verifyAndGetIsPrivileged(uid, packageName, null);
+ verifyAndGetBypass(uid, packageName, null);
return AppOpsManager.MODE_ALLOWED;
} catch (SecurityException ignored) {
@@ -2961,17 +2962,16 @@
@Nullable String featureId, int proxyUid, String proxyPackageName,
@Nullable String proxyFeatureId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp,
@Nullable String message) {
- boolean isPrivileged;
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
+ bypass = verifyAndGetBypass(uid, packageName, featureId);
} catch (SecurityException e) {
Slog.e(TAG, "noteOperation", e);
return AppOpsManager.MODE_ERRORED;
}
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
- true /* edit */);
+ final Ops ops = getOpsLocked(uid, packageName, featureId, bypass, true /* edit */);
if (ops == null) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
@@ -2981,7 +2981,7 @@
}
final Op op = getOpLocked(ops, code, uid, true);
final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
- if (isOpRestrictedLocked(uid, code, packageName, featureId, isPrivileged)) {
+ if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
return AppOpsManager.MODE_IGNORED;
@@ -3205,7 +3205,7 @@
int uid = Binder.getCallingUid();
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
- verifyAndGetIsPrivileged(uid, packageName, null);
+ verifyAndGetBypass(uid, packageName, null);
synchronized (this) {
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -3235,7 +3235,7 @@
int uid = Binder.getCallingUid();
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
- verifyAndGetIsPrivileged(uid, packageName, null);
+ verifyAndGetBypass(uid, packageName, null);
synchronized (this) {
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -3254,7 +3254,7 @@
int uid = Binder.getCallingUid();
- verifyAndGetIsPrivileged(uid, packageName, null);
+ verifyAndGetBypass(uid, packageName, null);
synchronized (this) {
return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
@@ -3272,16 +3272,16 @@
return AppOpsManager.MODE_IGNORED;
}
- boolean isPrivileged;
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
+ bypass = verifyAndGetBypass(uid, packageName, featureId);
} catch (SecurityException e) {
Slog.e(TAG, "startOperation", e);
return AppOpsManager.MODE_ERRORED;
}
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, resolvedPackageName, featureId, isPrivileged,
+ final Ops ops = getOpsLocked(uid, resolvedPackageName, featureId, bypass,
true /* edit */);
if (ops == null) {
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
@@ -3289,7 +3289,7 @@
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, uid, true);
- if (isOpRestrictedLocked(uid, code, resolvedPackageName, featureId, isPrivileged)) {
+ if (isOpRestrictedLocked(uid, code, resolvedPackageName, bypass)) {
return AppOpsManager.MODE_IGNORED;
}
final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
@@ -3347,16 +3347,16 @@
return;
}
- boolean isPrivileged;
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
+ bypass = verifyAndGetBypass(uid, packageName, featureId);
} catch (SecurityException e) {
Slog.e(TAG, "Cannot finishOperation", e);
return;
}
synchronized (this) {
- Op op = getOpLocked(code, uid, resolvedPackageName, featureId, isPrivileged, true);
+ Op op = getOpLocked(code, uid, resolvedPackageName, featureId, bypass, true);
if (op == null) {
return;
}
@@ -3617,7 +3617,22 @@
}
/**
- * Verify that package belongs to uid and return whether the package is privileged.
+ * Create a restriction description matching the properties of the package.
+ *
+ * @param context A context to use
+ * @param pkg The package to create the restriction description for
+ *
+ * @return The restriction matching the package
+ */
+ private RestrictionBypass getBypassforPackage(@NonNull AndroidPackage pkg) {
+ return new RestrictionBypass(pkg.isPrivileged(), mContext.checkPermission(
+ android.Manifest.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid())
+ == PackageManager.PERMISSION_GRANTED);
+ }
+
+ /**
+ * Verify that package belongs to uid and return the {@link RestrictionBypass bypass
+ * description} for the package.
*
* @param uid The uid the package belongs to
* @param packageName The package the might belong to the uid
@@ -3625,11 +3640,11 @@
*
* @return {@code true} iff the package is privileged
*/
- private boolean verifyAndGetIsPrivileged(int uid, String packageName,
+ private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName,
@Nullable String featureId) {
if (uid == Process.ROOT_UID) {
// For backwards compatibility, don't check package name for root UID.
- return false;
+ return null;
}
// Do not check if uid/packageName/featureId is already known
@@ -3638,13 +3653,14 @@
if (uidState != null && uidState.pkgOps != null) {
Ops ops = uidState.pkgOps.get(packageName);
- if (ops != null && (featureId == null || ops.knownFeatureIds.contains(featureId))) {
- return ops.isPrivileged;
+ if (ops != null && (featureId == null || ops.knownFeatureIds.contains(featureId))
+ && ops.bypass != null) {
+ return ops.bypass;
}
}
}
- boolean isPrivileged = false;
+ RestrictionBypass bypass = null;
final long ident = Binder.clearCallingIdentity();
try {
int pkgUid;
@@ -3668,14 +3684,14 @@
pkgUid = UserHandle.getUid(
UserHandle.getUserId(uid), UserHandle.getAppId(pkg.getUid()));
- isPrivileged = pkg.isPrivileged();
+ bypass = getBypassforPackage(pkg);
} else {
// Allow any feature id for resolvable uids
isFeatureIdValid = true;
pkgUid = resolveUid(packageName);
if (pkgUid >= 0) {
- isPrivileged = false;
+ bypass = RestrictionBypass.UNRESTRICTED;
}
}
if (pkgUid != uid) {
@@ -3692,7 +3708,7 @@
Binder.restoreCallingIdentity(ident);
}
- return isPrivileged;
+ return bypass;
}
/**
@@ -3701,13 +3717,13 @@
* @param uid The uid the package belongs to
* @param packageName The name of the package
* @param featureId The feature in the package
- * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
+ * @param bypass When to bypass certain op restrictions (can be null if edit == false)
* @param edit If an ops does not exist, create the ops?
- * @return
+ * @return The ops
*/
- private Ops getOpsRawLocked(int uid, String packageName, @Nullable String featureId,
- boolean isPrivileged, boolean edit) {
+ private Ops getOpsLocked(int uid, String packageName, @Nullable String featureId,
+ @Nullable RestrictionBypass bypass, boolean edit) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
return null;
@@ -3725,53 +3741,18 @@
if (!edit) {
return null;
}
- ops = new Ops(packageName, uidState, isPrivileged);
- uidState.pkgOps.put(packageName, ops);
- }
- if (edit && featureId != null) {
- ops.knownFeatureIds.add(featureId);
- }
- return ops;
- }
-
- /**
- * Get the state of all ops for a package.
- *
- * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
- *
- * @param uid The uid the of the package
- * @param packageName The package name for which to get the state for
- * @param featureId The feature in the package
- * @param edit Iff {@code true} create the {@link Ops} object if not yet created
- * @param isPrivileged Whether the package is privileged or not
- *
- * @return The {@link Ops state} of all ops for the package
- */
- private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
- @Nullable String featureId, boolean edit, boolean isPrivileged) {
- UidState uidState = getUidStateLocked(uid, edit);
- if (uidState == null) {
- return null;
- }
-
- if (uidState.pkgOps == null) {
- if (!edit) {
- return null;
- }
- uidState.pkgOps = new ArrayMap<>();
- }
-
- Ops ops = uidState.pkgOps.get(packageName);
- if (ops == null) {
- if (!edit) {
- return null;
- }
- ops = new Ops(packageName, uidState, isPrivileged);
+ ops = new Ops(packageName, uidState);
uidState.pkgOps.put(packageName, ops);
}
- if (edit && featureId != null) {
- ops.knownFeatureIds.add(featureId);
+ if (edit) {
+ if (bypass != null) {
+ ops.bypass = bypass;
+ }
+
+ if (featureId != null) {
+ ops.knownFeatureIds.add(featureId);
+ }
}
return ops;
@@ -3800,15 +3781,14 @@
* @param uid The uid the of the package
* @param packageName The package name for which to get the state for
* @param featureId The feature in the package
- * @param isPrivileged Whether the package is privileged or not (only used if {@code edit
- * == true})
+ * @param bypass When to bypass certain op restrictions (can be null if edit == false)
* @param edit Iff {@code true} create the {@link Op} object if not yet created
*
* @return The {@link Op state} of the op
*/
private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
- @Nullable String featureId, boolean isPrivileged, boolean edit) {
- Ops ops = getOpsRawNoVerifyLocked(uid, packageName, featureId, edit, isPrivileged);
+ @Nullable String featureId, @Nullable RestrictionBypass bypass, boolean edit) {
+ Ops ops = getOpsLocked(uid, packageName, featureId, bypass, edit);
if (ops == null) {
return null;
}
@@ -3839,7 +3819,7 @@
}
private boolean isOpRestrictedLocked(int uid, int code, String packageName,
- @Nullable String featureId, boolean isPrivileged) {
+ @Nullable RestrictionBypass appBypass) {
int userHandle = UserHandle.getUserId(uid);
final int restrictionSetCount = mOpUserRestrictions.size();
@@ -3848,12 +3828,15 @@
// package is exempt from the restriction.
ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
if (restrictionState.hasRestriction(code, packageName, userHandle)) {
- if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
+ RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
+ if (opBypass != null) {
// If we are the system, bypass user restrictions for certain codes
synchronized (this) {
- Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
- true /* edit */);
- if ((ops != null) && ops.isPrivileged) {
+ if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) {
+ return false;
+ }
+ if (opBypass.isRecordAudioRestrictionExcept && appBypass != null
+ && appBypass.isRecordAudioRestrictionExcept) {
return false;
}
}
@@ -4043,28 +4026,6 @@
throws NumberFormatException, XmlPullParserException, IOException {
int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
final UidState uidState = getUidStateLocked(uid, true);
- String isPrivilegedString = parser.getAttributeValue(null, "p");
- boolean isPrivileged = false;
- if (isPrivilegedString == null) {
- try {
- IPackageManager packageManager = ActivityThread.getPackageManager();
- if (packageManager != null) {
- ApplicationInfo appInfo = ActivityThread.getPackageManager()
- .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
- if (appInfo != null) {
- isPrivileged = (appInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
- }
- } else {
- // Could not load data, don't add to cache so it will be loaded later.
- return;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Could not contact PackageManager", e);
- }
- } else {
- isPrivileged = Boolean.parseBoolean(isPrivilegedString);
- }
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4074,7 +4035,7 @@
}
String tagName = parser.getName();
if (tagName.equals("op")) {
- readOp(parser, uidState, pkgName, isPrivileged);
+ readOp(parser, uidState, pkgName);
} else {
Slog.w(TAG, "Unknown element under <pkg>: "
+ parser.getName());
@@ -4108,8 +4069,8 @@
}
}
- private void readOp(XmlPullParser parser, @NonNull UidState uidState,
- @NonNull String pkgName, boolean isPrivileged) throws NumberFormatException,
+ private void readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName)
+ throws NumberFormatException,
XmlPullParserException, IOException {
int opCode = Integer.parseInt(parser.getAttributeValue(null, "n"));
if (isIgnoredAppOp(opCode)) {
@@ -4143,7 +4104,7 @@
}
Ops ops = uidState.pkgOps.get(pkgName);
if (ops == null) {
- ops = new Ops(pkgName, uidState, isPrivileged);
+ ops = new Ops(pkgName, uidState);
uidState.pkgOps.put(pkgName, ops);
}
ops.put(op.op, op);
@@ -4235,17 +4196,6 @@
}
out.startTag(null, "uid");
out.attribute(null, "n", Integer.toString(pkg.getUid()));
- synchronized (this) {
- Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), null,
- false /* isPrivileged */, false /* edit */);
- // Should always be present as the list of PackageOps is generated
- // from Ops.
- if (ops != null) {
- out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
- } else {
- out.attribute(null, "p", Boolean.toString(false));
- }
- }
List<AppOpsManager.OpEntry> ops = pkg.getOps();
for (int j=0; j<ops.size(); j++) {
AppOpsManager.OpEntry op = ops.get(j);
@@ -5574,7 +5524,7 @@
}
// TODO moltmann: Allow to check for feature op activeness
synchronized (AppOpsService.this) {
- Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false, false);
+ Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false);
if (pkgOps == null) {
return false;
}
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 61bede9..b2ea311 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -314,6 +314,63 @@
}
}
+ private long[] getAllowedChangesAfterTargetSdkForPackage(String packageName,
+ int targetSdkVersion)
+ throws RemoteException {
+ LongArray allowed = new LongArray();
+ synchronized (mChanges) {
+ for (int i = 0; i < mChanges.size(); ++i) {
+ try {
+ CompatChange change = mChanges.valueAt(i);
+ if (change.getEnableAfterTargetSdk() != targetSdkVersion) {
+ continue;
+ }
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(change.getId(),
+ packageName);
+ if (allowedState.state == OverrideAllowedState.ALLOWED) {
+ allowed.add(change.getId());
+ }
+ } catch (RemoteException e) {
+ // Should never occur, since validator is in the same process.
+ throw new RuntimeException("Unable to call override validator!", e);
+ }
+ }
+ }
+ return allowed.toArray();
+ }
+
+ /**
+ * Enables all changes with enabledAfterTargetSdk == {@param targetSdkVersion} for
+ * {@param packageName}.
+ *
+ * @return The number of changes that were toggled.
+ */
+ int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
+ throws RemoteException {
+ long[] changes = getAllowedChangesAfterTargetSdkForPackage(packageName, targetSdkVersion);
+ for (long changeId : changes) {
+ addOverride(changeId, packageName, true);
+ }
+ return changes.length;
+ }
+
+
+ /**
+ * Disables all changes with enabledAfterTargetSdk == {@param targetSdkVersion} for
+ * {@param packageName}.
+ *
+ * @return The number of changes that were toggled.
+ */
+ int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
+ throws RemoteException {
+ long[] changes = getAllowedChangesAfterTargetSdkForPackage(packageName, targetSdkVersion);
+ for (long changeId : changes) {
+ addOverride(changeId, packageName, false);
+ }
+ return changes.length;
+ }
+
boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
boolean alreadyKnown = true;
synchronized (mChanges) {
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 821653a..8519b00 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -166,6 +166,26 @@
}
@Override
+ public int enableTargetSdkChanges(String packageName, int targetSdkVersion)
+ throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
+ int numChanges = mCompatConfig.enableTargetSdkChangesForPackage(packageName,
+ targetSdkVersion);
+ killPackage(packageName);
+ return numChanges;
+ }
+
+ @Override
+ public int disableTargetSdkChanges(String packageName, int targetSdkVersion)
+ throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
+ int numChanges = mCompatConfig.disableTargetSdkChangesForPackage(packageName,
+ targetSdkVersion);
+ killPackage(packageName);
+ return numChanges;
+ }
+
+ @Override
public void clearOverrides(String packageName) throws RemoteException, SecurityException {
checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index b456737..2aa53cc 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -60,6 +60,8 @@
private Connection mActiveConnection;
private boolean mConnectionReady;
+ private RouteDiscoveryPreference mPendingDiscoveryPreference = null;
+
MediaRoute2ProviderServiceProxy(@NonNull Context context, @NonNull ComponentName componentName,
int userId) {
super(componentName);
@@ -99,6 +101,8 @@
if (mConnectionReady) {
mActiveConnection.updateDiscoveryPreference(discoveryPreference);
updateBinding();
+ } else {
+ mPendingDiscoveryPreference = discoveryPreference;
}
}
@@ -271,6 +275,10 @@
private void onConnectionReady(Connection connection) {
if (mActiveConnection == connection) {
mConnectionReady = true;
+ if (mPendingDiscoveryPreference != null) {
+ updateDiscoveryPreference(mPendingDiscoveryPreference);
+ mPendingDiscoveryPreference = null;
+ }
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index ee5a4fe..4af31b0 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -306,9 +306,8 @@
/** Data layer operation counters for splicing into other structures. */
private NetworkStats mUidOperations = new NetworkStats(0L, 10);
- /** Must be set in factory by calling #setHandler. */
- private Handler mHandler;
- private Handler.Callback mHandlerCallback;
+ @NonNull
+ private final Handler mHandler;
private volatile boolean mSystemReady;
private long mPersistThreshold = 2 * MB_IN_BYTES;
@@ -324,6 +323,9 @@
private final static int DUMP_STATS_SESSION_COUNT = 20;
+ @NonNull
+ private final Dependencies mDeps;
+
private static @NonNull File getDefaultSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}
@@ -339,9 +341,24 @@
Clock.systemUTC());
}
- private static final class NetworkStatsHandler extends Handler {
- NetworkStatsHandler(Looper looper, Handler.Callback callback) {
- super(looper, callback);
+ private final class NetworkStatsHandler extends Handler {
+ NetworkStatsHandler(@NonNull Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PERFORM_POLL: {
+ performPoll(FLAG_PERSIST_ALL);
+ break;
+ }
+ case MSG_PERFORM_POLL_REGISTER_ALERT: {
+ performPoll(FLAG_PERSIST_NETWORK);
+ registerGlobalAlert();
+ break;
+ }
+ }
}
}
@@ -355,14 +372,10 @@
NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager,
wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class),
new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(),
- new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir());
+ new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(),
+ new Dependencies());
service.registerLocalService();
- HandlerThread handlerThread = new HandlerThread(TAG);
- Handler.Callback callback = new HandlerCallback(service);
- handlerThread.start();
- Handler handler = new NetworkStatsHandler(handlerThread.getLooper(), callback);
- service.setHandler(handler, callback);
return service;
}
@@ -373,7 +386,7 @@
AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock,
TelephonyManager teleManager, NetworkStatsSettings settings,
NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir,
- File baseDir) {
+ File baseDir, @NonNull Dependencies deps) {
mContext = Objects.requireNonNull(context, "missing Context");
mNetworkManager = Objects.requireNonNull(networkManager,
"missing INetworkManagementService");
@@ -387,6 +400,26 @@
mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir");
mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir");
mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists();
+ mDeps = Objects.requireNonNull(deps, "missing Dependencies");
+
+ final HandlerThread handlerThread = mDeps.makeHandlerThread();
+ handlerThread.start();
+ mHandler = new NetworkStatsHandler(handlerThread.getLooper());
+ }
+
+ /**
+ * Dependencies of NetworkStatsService, for injection in tests.
+ */
+ // TODO: Move more stuff into dependencies object.
+ @VisibleForTesting
+ public static class Dependencies {
+ /**
+ * Create a HandlerThread to use in NetworkStatsService.
+ */
+ @NonNull
+ public HandlerThread makeHandlerThread() {
+ return new HandlerThread(TAG);
+ }
}
private void registerLocalService() {
@@ -394,12 +427,6 @@
new NetworkStatsManagerInternalImpl());
}
- @VisibleForTesting
- void setHandler(Handler handler, Handler.Callback callback) {
- mHandler = handler;
- mHandlerCallback = callback;
- }
-
public void systemReady() {
synchronized (mStatsLock) {
mSystemReady = true;
@@ -1920,33 +1947,6 @@
}
- @VisibleForTesting
- static class HandlerCallback implements Handler.Callback {
- private final NetworkStatsService mService;
-
- HandlerCallback(NetworkStatsService service) {
- this.mService = service;
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_PERFORM_POLL: {
- mService.performPoll(FLAG_PERSIST_ALL);
- return true;
- }
- case MSG_PERFORM_POLL_REGISTER_ALERT: {
- mService.performPoll(FLAG_PERSIST_NETWORK);
- mService.registerGlobalAlert();
- return true;
- }
- default: {
- return false;
- }
- }
- }
- }
-
private void assertSystemReady() {
if (!mSystemReady) {
throw new IllegalStateException("System not ready");
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index b90681d..79a4da2 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -388,7 +388,7 @@
for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) {
IntentFilter intentFilter = intents.get(i);
if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(),
- intent.getData(), intent.getCategories(), "AppsFilter") > 0) {
+ intent.getData(), intent.getCategories(), "AppsFilter", true) > 0) {
return true;
}
}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index ec9b37d..83da381 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -45,6 +45,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -183,7 +184,8 @@
String callingFeatureId,
Intent intent,
@UserIdInt int userId,
- IBinder callingActivity) throws RemoteException {
+ IBinder callingActivity,
+ Bundle options) throws RemoteException {
Objects.requireNonNull(callingPackage);
Objects.requireNonNull(intent);
Objects.requireNonNull(intent.getComponent(), "The intent must have a Component set");
@@ -226,7 +228,7 @@
launchIntent,
callingActivity,
/* startFlags= */ 0,
- /* options= */ null,
+ options,
userId);
logStartActivityByIntent(callingPackage);
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 2d16854..62541ab 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5450,7 +5450,7 @@
packagePermissions, sharedUserPermissions);
}
- mPersistence.writeAsUser(runtimePermissions, UserHandle.of(userId));
+ mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId));
}
@NonNull
@@ -5504,12 +5504,12 @@
}
public void deleteUserRuntimePermissionsFile(int userId) {
- mPersistence.deleteAsUser(UserHandle.of(userId));
+ mPersistence.deleteForUser(UserHandle.of(userId));
}
@GuardedBy("Settings.this.mLock")
public void readStateForUserSyncLPr(int userId) {
- RuntimePermissionsState runtimePermissions = mPersistence.readAsUser(UserHandle.of(
+ RuntimePermissionsState runtimePermissions = mPersistence.readForUser(UserHandle.of(
userId));
if (runtimePermissions == null) {
readLegacyStateForUserSyncLPr(userId);
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 97ce6bd..b33dc8f 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -364,12 +364,12 @@
(Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked());
}
- mPersistence.writeAsUser(roles, UserHandle.of(mUserId));
+ mPersistence.writeForUser(roles, UserHandle.of(mUserId));
}
private void readFile() {
synchronized (mLock) {
- RolesState roles = mPersistence.readAsUser(UserHandle.of(mUserId));
+ RolesState roles = mPersistence.readForUser(UserHandle.of(mUserId));
if (roles == null) {
readLegacyFileLocked();
scheduleWriteFileLocked();
@@ -545,7 +545,7 @@
throw new IllegalStateException("This RoleUserState has already been destroyed");
}
mWriteHandler.removeCallbacksAndMessages(null);
- mPersistence.deleteAsUser(UserHandle.of(mUserId));
+ mPersistence.deleteForUser(UserHandle.of(mUserId));
mDestroyed = true;
}
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 6eb3c0f..a298b89 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2184,47 +2184,6 @@
}
}
- /**
- * Called when the wallpaper needs to zoom out.
- *
- * @param zoom from 0 to 1 (inclusive) where 1 means fully zoomed out, 0 means fully zoomed in.
- * @param callingPackage package name calling this API.
- * @param displayId id of the display whose zoom is updating.
- */
- public void setWallpaperZoomOut(float zoom, String callingPackage, int displayId) {
- if (!isWallpaperSupported(callingPackage)) {
- return;
- }
- synchronized (mLock) {
- if (!isValidDisplay(displayId)) {
- throw new IllegalArgumentException("Cannot find display with id=" + displayId);
- }
- int userId = UserHandle.getCallingUserId();
- if (mCurrentUserId != userId) {
- return; // Don't change the properties now
- }
- WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
- if (zoom < 0 || zoom > 1f) {
- throw new IllegalArgumentException("zoom must be between 0 and one: " + zoom);
- }
-
- if (wallpaper.connection != null) {
- final WallpaperConnection.DisplayConnector connector = wallpaper.connection
- .getDisplayConnectorOrCreate(displayId);
- final IWallpaperEngine engine = connector != null ? connector.mEngine : null;
- if (engine != null) {
- try {
- engine.setZoomOut(zoom);
- } catch (RemoteException e) {
- if (DEBUG) {
- Slog.w(TAG, "Couldn't set wallpaper zoom", e);
- }
- }
- }
- }
- }
- }
-
@Deprecated
@Override
public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb,
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 0e391f0..9bad799 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -647,14 +647,6 @@
if (prevWindowingMode != getWindowingMode()) {
mDisplayContent.onStackWindowingModeChanged(this);
-
- if (inSplitScreenSecondaryWindowingMode()) {
- // When the stack is resized due to entering split screen secondary, offset the
- // windows to compensate for the new stack position.
- forAllWindows(w -> {
- w.mWinAnimator.setOffsetPositionForStackResize(true);
- }, true);
- }
}
final DisplayContent display = getDisplay();
@@ -3883,9 +3875,10 @@
return;
}
if (mTile != null) {
- reparentSurfaceControl(getPendingTransaction(), mTile.getSurfaceControl());
+ // don't use reparentSurfaceControl because we need to bypass taskorg check
+ mSurfaceAnimator.reparent(getPendingTransaction(), mTile.getSurfaceControl());
} else if (mTile == null && origTile != null) {
- reparentSurfaceControl(getPendingTransaction(), getParentSurfaceControl());
+ mSurfaceAnimator.reparent(getPendingTransaction(), getParentSurfaceControl());
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 688c9ae..c7a1391 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -29,7 +29,6 @@
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.WaitResult.LAUNCH_STATE_COLD;
import static android.app.WaitResult.LAUNCH_STATE_HOT;
-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;
@@ -178,6 +177,9 @@
private Intent mNewTaskIntent;
private ActivityStack mSourceStack;
private ActivityStack mTargetStack;
+ // The task that the last activity was started into. We currently reset the actual start
+ // activity's task and as a result may not have a reference to the task in all cases
+ private Task mTargetTask;
private boolean mMovedToFront;
private boolean mNoAnimation;
private boolean mKeepCurTransition;
@@ -545,6 +547,7 @@
mNewTaskIntent = starter.mNewTaskIntent;
mSourceStack = starter.mSourceStack;
+ mTargetTask = starter.mTargetTask;
mTargetStack = starter.mTargetStack;
mMovedToFront = starter.mMovedToFront;
mNoAnimation = starter.mNoAnimation;
@@ -1368,7 +1371,10 @@
// it waits for the new activity to become visible instead, {@link #waitResultIfNeeded}.
mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result);
- if (startedActivityStack == null) {
+ final Task targetTask = r.getTask() != null
+ ? r.getTask()
+ : mTargetTask;
+ if (startedActivityStack == null || targetTask == null) {
return;
}
@@ -1379,19 +1385,10 @@
// The activity was already running so it wasn't started, but either brought to the
// front or the new intent was delivered to it since it was already in front. Notify
// anyone interested in this piece of information.
- switch (startedActivityStack.getWindowingMode()) {
- case WINDOWING_MODE_PINNED:
- mService.getTaskChangeNotificationController().notifyPinnedActivityRestartAttempt(
- clearedTask);
- break;
- case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
- final ActivityStack homeStack =
- startedActivityStack.getDisplay().getOrCreateRootHomeTask();
- if (homeStack != null && homeStack.shouldBeVisible(null /* starting */)) {
- mService.mWindowManager.showRecentApps();
- }
- break;
- }
+ final ActivityStack homeStack = targetTask.getDisplayContent().getRootHomeTask();
+ final boolean homeTaskVisible = homeStack != null && homeStack.shouldBeVisible(null);
+ mService.getTaskChangeNotificationController().notifyActivityRestartAttempt(
+ targetTask.getTaskInfo(), homeTaskVisible, clearedTask);
}
}
@@ -1517,6 +1514,7 @@
// Compute if there is an existing task that should be used for.
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
final boolean newTask = targetTask == null;
+ mTargetTask = targetTask;
computeLaunchParams(r, sourceRecord, targetTask);
@@ -2018,6 +2016,7 @@
mSourceStack = null;
mTargetStack = null;
+ mTargetTask = null;
mMovedToFront = false;
mNoAnimation = false;
mKeepCurTransition = false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index d3ff912..7bacc42 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -288,6 +288,7 @@
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -355,6 +356,8 @@
ActivityManagerInternal mAmInternal;
UriGrantsManagerInternal mUgmInternal;
private PackageManagerInternal mPmInternal;
+ /** The cached sys ui service component name from package manager. */
+ private ComponentName mSysUiServiceComponent;
private PermissionPolicyInternal mPermissionPolicyInternal;
@VisibleForTesting
final ActivityTaskManagerInternal mInternal;
@@ -680,7 +683,7 @@
}
@Override
- public void onChange(boolean selfChange, Iterable<Uri> uris, int flags,
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags,
@UserIdInt int userId) {
for (Uri uri : uris) {
if (mFontScaleUri.equals(uri)) {
@@ -5868,6 +5871,14 @@
return mPmInternal;
}
+ ComponentName getSysUiServiceComponentLocked() {
+ if (mSysUiServiceComponent == null) {
+ final PackageManagerInternal pm = getPackageManagerInternalLocked();
+ mSysUiServiceComponent = pm.getSystemUiServiceComponent();
+ }
+ return mSysUiServiceComponent;
+ }
+
PermissionPolicyInternal getPermissionPolicyInternal() {
if (mPermissionPolicyInternal == null) {
mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3352bd5..98e3d07 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2224,9 +2224,7 @@
.addTaggedData(MetricsEvent.FIELD_DISPLAY_ID, getDisplayId()));
}
- // If there was no pinned stack, we still need to notify the controller of the display info
- // update as a result of the config change.
- if (mPinnedStackControllerLocked != null && !hasPinnedTask()) {
+ if (mPinnedStackControllerLocked != null) {
mPinnedStackControllerLocked.onDisplayInfoChanged(getDisplayInfo());
}
}
@@ -4934,6 +4932,12 @@
scheduleAnimation();
}
}
+
+ @Override
+ boolean shouldMagnify() {
+ // Omitted from Screen-Magnification
+ return false;
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index d5a0d05..ba61667 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -28,6 +28,7 @@
import static android.view.InsetsState.ITYPE_BOTTOM_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES;
import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
+import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_LEFT_DISPLAY_CUTOUT;
import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
@@ -439,10 +440,12 @@
updateDreamingSleepToken(msg.arg1 != 0);
break;
case MSG_REQUEST_TRANSIENT_BARS:
- WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
- ? mStatusBar : mNavigationBar;
- if (targetBar != null) {
- requestTransientBars(targetBar);
+ synchronized (mLock) {
+ WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
+ ? mStatusBar : mNavigationBar;
+ if (targetBar != null) {
+ requestTransientBars(targetBar);
+ }
}
break;
case MSG_DISPOSE_INPUT_CONSUMER:
@@ -498,15 +501,20 @@
new SystemGesturesPointerEventListener.Callbacks() {
@Override
public void onSwipeFromTop() {
- if (mStatusBar != null) {
- requestTransientBars(mStatusBar);
+ synchronized (mLock) {
+ if (mStatusBar != null) {
+ requestTransientBars(mStatusBar);
+ }
}
}
@Override
public void onSwipeFromBottom() {
- if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
- requestTransientBars(mNavigationBar);
+ synchronized (mLock) {
+ if (mNavigationBar != null
+ && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+ requestTransientBars(mNavigationBar);
+ }
}
}
@@ -516,12 +524,13 @@
synchronized (mLock) {
mDisplayContent.calculateSystemGestureExclusion(
excludedRegion, null /* outUnrestricted */);
- }
- final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
- || mNavigationBarPosition == NAV_BAR_RIGHT;
- if (mNavigationBar != null && sideAllowed
- && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
- requestTransientBars(mNavigationBar);
+ final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
+ || mNavigationBarPosition == NAV_BAR_RIGHT;
+ if (mNavigationBar != null && sideAllowed
+ && !mSystemGestures.currentGestureStartedInRegion(
+ excludedRegion)) {
+ requestTransientBars(mNavigationBar);
+ }
}
excludedRegion.recycle();
}
@@ -532,12 +541,13 @@
synchronized (mLock) {
mDisplayContent.calculateSystemGestureExclusion(
excludedRegion, null /* outUnrestricted */);
- }
- final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
- || mNavigationBarPosition == NAV_BAR_LEFT;
- if (mNavigationBar != null && sideAllowed
- && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
- requestTransientBars(mNavigationBar);
+ final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
+ || mNavigationBarPosition == NAV_BAR_LEFT;
+ if (mNavigationBar != null && sideAllowed
+ && !mSystemGestures.currentGestureStartedInRegion(
+ excludedRegion)) {
+ requestTransientBars(mNavigationBar);
+ }
}
excludedRegion.recycle();
}
@@ -1469,8 +1479,14 @@
*/
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
displayFrames.onBeginLayout();
- updateInsetsStateForDisplayCutout(displayFrames,
- mDisplayContent.getInsetsStateController().getRawInsetsState());
+ final InsetsState insetsState =
+ mDisplayContent.getInsetsStateController().getRawInsetsState();
+
+ // Reset the frame of IME so that the layout of windows above IME won't get influenced.
+ // Once we layout the IME, frames will be set again on the source.
+ insetsState.getSource(ITYPE_IME).setFrame(0, 0, 0, 0);
+
+ updateInsetsStateForDisplayCutout(displayFrames, insetsState);
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
@@ -3149,47 +3165,46 @@
}
private void requestTransientBars(WindowState swipeTarget) {
- synchronized (mLock) {
- if (!mService.mPolicy.isUserSetupComplete()) {
- // Swipe-up for navigation bar is disabled during setup
+ if (!mService.mPolicy.isUserSetupComplete()) {
+ // Swipe-up for navigation bar is disabled during setup
+ return;
+ }
+ if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
+ if (swipeTarget == mNavigationBar
+ && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
+ // Don't show status bar when swiping on already visible navigation bar
return;
}
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- if (swipeTarget == mNavigationBar
- && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
- // Don't show status bar when swiping on already visible navigation bar
- return;
- }
- final InsetsControlTarget controlTarget =
- swipeTarget.getControllableInsetProvider().getControlTarget();
+ final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
+ final InsetsControlTarget controlTarget = provider != null
+ ? provider.getControlTarget() : null;
- // No transient mode on lockscreen (in notification shade window).
- if (controlTarget == null || controlTarget == getNotificationShade()) {
+ // No transient mode on lockscreen (in notification shade window).
+ if (controlTarget == null || controlTarget == getNotificationShade()) {
+ return;
+ }
+ if (controlTarget.canShowTransient()) {
+ mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
+ new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ } else {
+ controlTarget.showInsets(Type.systemBars(), false);
+ }
+ } else {
+ boolean sb = mStatusBarController.checkShowTransientBarLw();
+ boolean nb = mNavigationBarController.checkShowTransientBarLw()
+ && !isNavBarEmpty(mLastSystemUiFlags);
+ if (sb || nb) {
+ // Don't show status bar when swiping on already visible navigation bar
+ if (!nb && swipeTarget == mNavigationBar) {
+ if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
return;
}
- if (controlTarget.canShowTransient()) {
- mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
- } else {
- controlTarget.showInsets(Type.systemBars(), false);
- }
- } else {
- boolean sb = mStatusBarController.checkShowTransientBarLw();
- boolean nb = mNavigationBarController.checkShowTransientBarLw()
- && !isNavBarEmpty(mLastSystemUiFlags);
- if (sb || nb) {
- // Don't show status bar when swiping on already visible navigation bar
- if (!nb && swipeTarget == mNavigationBar) {
- if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
- return;
- }
- if (sb) mStatusBarController.showTransient();
- if (nb) mNavigationBarController.showTransient();
- updateSystemUiVisibilityLw();
- }
+ if (sb) mStatusBarController.showTransient();
+ if (nb) mNavigationBarController.showTransient();
+ updateSystemUiVisibilityLw();
}
- mImmersiveModeConfirmation.confirmCurrentPrompt();
}
+ mImmersiveModeConfirmation.confirmCurrentPrompt();
}
private void disposeInputConsumer(InputConsumer inputConsumer) {
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 6ff029b..ee36db9 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_INVALID;
@@ -29,6 +30,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.app.WindowConfiguration.WindowingMode;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -74,30 +77,28 @@
/**
* When dispatching window state to the client, we'll need to exclude the source that represents
- * the window that is being dispatched.
+ * the window that is being dispatched. We also need to exclude certain types of insets source
+ * for client within specific windowing modes.
*
* @param target The client we dispatch the state to.
* @return The state stripped of the necessary information.
*/
InsetsState getInsetsForDispatch(@NonNull WindowState target) {
final InsetsSourceProvider provider = target.getControllableInsetProvider();
- if (provider == null) {
- return mState;
- }
- final @InternalInsetsType int type = provider.getSource().getType();
- return getInsetsForType(type);
+ final @InternalInsetsType int type = provider != null
+ ? provider.getSource().getType() : ITYPE_INVALID;
+ return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode());
}
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
final @InternalInsetsType int type = getInsetsTypeForWindowType(attrs.type);
- if (type == ITYPE_INVALID) {
- return mState;
- }
- return getInsetsForType(type);
+ final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
+ final @WindowingMode int windowingMode = token != null
+ ? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
+ return getInsetsForTypeAndWindowingMode(type, windowingMode);
}
- @InternalInsetsType
- private static int getInsetsTypeForWindowType(int type) {
+ private static @InternalInsetsType int getInsetsTypeForWindowType(int type) {
switch(type) {
case TYPE_STATUS_BAR:
return ITYPE_STATUS_BAR;
@@ -110,36 +111,48 @@
}
}
- private InsetsState getInsetsForType(@InternalInsetsType int type) {
- final InsetsState state = new InsetsState();
- state.set(mState);
- state.removeSource(type);
+ /** @see #getInsetsForDispatch */
+ private InsetsState getInsetsForTypeAndWindowingMode(@InternalInsetsType int type,
+ @WindowingMode int windowingMode) {
+ InsetsState state = mState;
- // Navigation bar doesn't get influenced by anything else
- if (type == ITYPE_NAVIGATION_BAR) {
- state.removeSource(ITYPE_IME);
- state.removeSource(ITYPE_STATUS_BAR);
- state.removeSource(ITYPE_CAPTION_BAR);
- }
+ if (type != ITYPE_INVALID) {
+ state = new InsetsState(state);
+ state.removeSource(type);
- // Status bar doesn't get influenced by caption bar
- if (type == ITYPE_STATUS_BAR) {
- state.removeSource(ITYPE_CAPTION_BAR);
- }
+ // Navigation bar doesn't get influenced by anything else
+ if (type == ITYPE_NAVIGATION_BAR) {
+ state.removeSource(ITYPE_IME);
+ state.removeSource(ITYPE_STATUS_BAR);
+ state.removeSource(ITYPE_CAPTION_BAR);
+ }
- // IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
- if (type == ITYPE_IME) {
- for (int i = mProviders.size() - 1; i >= 0; i--) {
- InsetsSourceProvider otherProvider = mProviders.valueAt(i);
- if (otherProvider.overridesImeFrame()) {
- InsetsSource override =
- new InsetsSource(state.getSource(otherProvider.getSource().getType()));
- override.setFrame(otherProvider.getImeOverrideFrame());
- state.addSource(override);
+ // Status bar doesn't get influenced by caption bar
+ if (type == ITYPE_STATUS_BAR) {
+ state.removeSource(ITYPE_CAPTION_BAR);
+ }
+
+ // IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
+ if (type == ITYPE_IME) {
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ InsetsSourceProvider otherProvider = mProviders.valueAt(i);
+ if (otherProvider.overridesImeFrame()) {
+ InsetsSource override =
+ new InsetsSource(
+ state.getSource(otherProvider.getSource().getType()));
+ override.setFrame(otherProvider.getImeOverrideFrame());
+ state.addSource(override);
+ }
}
}
}
+ if (WindowConfiguration.isFloating(windowingMode)) {
+ state = new InsetsState(state);
+ state.removeSource(ITYPE_STATUS_BAR);
+ state.removeSource(ITYPE_NAVIGATION_BAR);
+ }
+
return state;
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 9df4248..5f3732a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -356,6 +356,31 @@
}
@Override
+ public void setWallpaperZoomOut(IBinder window, float zoom) {
+ if (Float.compare(0f, zoom) > 0 || Float.compare(1f, zoom) < 0 || Float.isNaN(zoom)) {
+ throw new IllegalArgumentException("Zoom must be a valid float between 0 and 1: "
+ + zoom);
+ }
+ synchronized (mService.mGlobalLock) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ actionOnWallpaper(window, (wpController, windowState) ->
+ wpController.setWallpaperZoomOut(windowState, zoom));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
+ public void setShouldZoomOutWallpaper(IBinder window, boolean shouldZoom) {
+ synchronized (mService.mGlobalLock) {
+ actionOnWallpaper(window, (wpController, windowState) ->
+ wpController.setShouldZoomOutWallpaper(windowState, shouldZoom));
+ }
+ }
+
+ @Override
public void wallpaperOffsetsComplete(IBinder window) {
synchronized (mService.mGlobalLock) {
actionOnWallpaper(window, (wpController, windowState) ->
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a9a4d9f..5ed903e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3971,12 +3971,12 @@
boolean isControlledByTaskOrganizer() {
final Task rootTask = getRootTask();
- return rootTask == this && rootTask.mTaskOrganizer != null
- // TODO(task-hierarchy): Figure out how to control nested tasks.
- // For now, if this is in a tile let WM drive.
- && !(rootTask instanceof TaskTile)
- && !(rootTask instanceof ActivityStack
- && ((ActivityStack) rootTask).getTile() != null);
+ // if the rootTask is a "child" of a tile, then don't consider it a root task.
+ // TODO: remove this along with removing tile.
+ if (((ActivityStack) rootTask).getTile() != null) {
+ return false;
+ }
+ return rootTask == this && rootTask.mTaskOrganizer != null;
}
@Override
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 96a9127..e4f10d9 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -30,13 +30,15 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import com.android.internal.os.SomeArgs;
+
import java.util.ArrayList;
class TaskChangeNotificationController {
private static final int LOG_STACK_STATE_MSG = 1;
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 2;
private static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 3;
- private static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
+ private static final int NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
private static final int NOTIFY_FORCED_RESIZABLE_MSG = 6;
private static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 7;
private static final int NOTIFY_TASK_ADDED_LISTENERS_MSG = 8;
@@ -118,8 +120,10 @@
l.onActivityUnpinned();
};
- private final TaskStackConsumer mNotifyPinnedActivityRestartAttempt = (l, m) -> {
- l.onPinnedActivityRestartAttempt(m.arg1 != 0);
+ private final TaskStackConsumer mNotifyActivityRestartAttempt = (l, m) -> {
+ SomeArgs args = (SomeArgs) m.obj;
+ l.onActivityRestartAttempt((RunningTaskInfo) args.arg1, args.argi1 != 0,
+ args.argi2 != 0);
};
private final TaskStackConsumer mNotifyActivityForcedResizable = (l, m) -> {
@@ -220,8 +224,8 @@
case NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG:
forAllRemoteListeners(mNotifyActivityUnpinned, msg);
break;
- case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG:
- forAllRemoteListeners(mNotifyPinnedActivityRestartAttempt, msg);
+ case NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG:
+ forAllRemoteListeners(mNotifyActivityRestartAttempt, msg);
break;
case NOTIFY_FORCED_RESIZABLE_MSG:
forAllRemoteListeners(mNotifyActivityForcedResizable, msg);
@@ -266,6 +270,9 @@
forAllRemoteListeners(mNotifyTaskFocusChanged, msg);
break;
}
+ if (msg.obj instanceof SomeArgs) {
+ ((SomeArgs) msg.obj).recycle();
+ }
}
}
@@ -358,15 +365,18 @@
/**
* Notifies all listeners when an attempt was made to start an an activity that is already
- * running in the pinned stack and the activity was not actually started, but the task is
- * either brought to the front or a new Intent is delivered to it.
+ * running, but the task is either brought to the front or a new Intent is delivered to it.
*/
- void notifyPinnedActivityRestartAttempt(boolean clearedTask) {
- mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
- final Message msg =
- mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG,
- clearedTask ? 1 : 0, 0);
- forAllLocalListeners(mNotifyPinnedActivityRestartAttempt, msg);
+ void notifyActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) {
+ mHandler.removeMessages(NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = task;
+ args.argi1 = homeTaskVisible ? 1 : 0;
+ args.argi2 = clearedTask ? 1 : 0;
+ final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG,
+ args);
+ forAllLocalListeners(mNotifyActivityRestartAttempt, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index aa17666..cfb5706 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -128,7 +128,7 @@
void removeTask(Task t) {
try {
- mOrganizer.taskVanished(t.getRemoteToken());
+ mOrganizer.taskVanished(t.getTaskInfo());
} catch (Exception e) {
Slog.e(TAG, "Exception sending taskVanished callback" + e);
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 669eb78..57d0a33 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -41,6 +41,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArraySet;
+import android.util.MathUtils;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.SurfaceControl;
@@ -52,6 +53,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.function.Consumer;
/**
* Controls wallpaper windows visibility, ordering, and so on.
@@ -75,8 +77,10 @@
private float mLastWallpaperY = -1;
private float mLastWallpaperXStep = -1;
private float mLastWallpaperYStep = -1;
+ private float mLastWallpaperZoomOut = 0;
private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
+ private final float mMaxWallpaperScale;
// This is set when we are waiting for a wallpaper to tell us it is done
// changing its scroll position.
@@ -191,9 +195,21 @@
return false;
};
+ /**
+ * @see #computeLastWallpaperZoomOut()
+ */
+ private Consumer<WindowState> mComputeMaxZoomOutFunction = windowState -> {
+ if (!windowState.mIsWallpaper
+ && Float.compare(windowState.mWallpaperZoomOut, mLastWallpaperZoomOut) > 0) {
+ mLastWallpaperZoomOut = windowState.mWallpaperZoomOut;
+ }
+ };
+
WallpaperController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
+ mMaxWallpaperScale = service.mContext.getResources()
+ .getFloat(com.android.internal.R.dimen.config_wallpaperMaxScale);
}
WindowState getWallpaperTarget() {
@@ -325,20 +341,30 @@
rawChanged = true;
}
- boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset);
+ if (Float.compare(wallpaperWin.mWallpaperZoomOut, mLastWallpaperZoomOut) != 0) {
+ wallpaperWin.mWallpaperZoomOut = mLastWallpaperZoomOut;
+ rawChanged = true;
+ }
+
+ boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset,
+ wallpaperWin.mShouldScaleWallpaper
+ ? zoomOutToScale(wallpaperWin.mWallpaperZoomOut) : 1);
if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
try {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
+ wallpaperWin + " x=" + wallpaperWin.mWallpaperX
- + " y=" + wallpaperWin.mWallpaperY);
+ + " y=" + wallpaperWin.mWallpaperY
+ + " zoom=" + wallpaperWin.mWallpaperZoomOut);
if (sync) {
mWaitingOnWallpaper = wallpaperWin;
}
wallpaperWin.mClient.dispatchWallpaperOffsets(
wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY,
- wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync);
+ wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep,
+ wallpaperWin.mWallpaperZoomOut, sync);
+
if (sync) {
if (mWaitingOnWallpaper != null) {
long start = SystemClock.uptimeMillis();
@@ -378,6 +404,20 @@
}
}
+ void setWallpaperZoomOut(WindowState window, float zoom) {
+ if (Float.compare(window.mWallpaperZoomOut, zoom) != 0) {
+ window.mWallpaperZoomOut = zoom;
+ updateWallpaperOffsetLocked(window, false);
+ }
+ }
+
+ void setShouldZoomOutWallpaper(WindowState window, boolean shouldZoom) {
+ if (shouldZoom != window.mShouldScaleWallpaper) {
+ window.mShouldScaleWallpaper = shouldZoom;
+ updateWallpaperOffsetLocked(window, false);
+ }
+ }
+
void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) {
if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) {
window.mWallpaperDisplayOffsetX = x;
@@ -420,6 +460,7 @@
} else if (changingTarget.mWallpaperY >= 0) {
mLastWallpaperY = changingTarget.mWallpaperY;
}
+ computeLastWallpaperZoomOut();
if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
} else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
@@ -593,6 +634,9 @@
mLastWallpaperX = mWallpaperTarget.mWallpaperX;
mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
}
+ if (mWallpaperTarget.mWallpaperZoomOut >= 0) {
+ mLastWallpaperZoomOut = mWallpaperTarget.mWallpaperZoomOut;
+ }
if (mWallpaperTarget.mWallpaperY >= 0) {
mLastWallpaperY = mWallpaperTarget.mWallpaperY;
mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
@@ -762,6 +806,23 @@
return mTmpTopWallpaper;
}
+ /**
+ * Each window can request a zoom, example:
+ * - User is in overview, zoomed out.
+ * - User also pulls down the shade.
+ *
+ * This means that we always have to choose the largest zoom out that we have, otherwise
+ * we'll have conflicts and break the "depth system" mental model.
+ */
+ private void computeLastWallpaperZoomOut() {
+ mLastWallpaperZoomOut = 0;
+ mDisplayContent.forAllWindows(mComputeMaxZoomOutFunction, true);
+ }
+
+ private float zoomOutToScale(float zoom) {
+ return MathUtils.lerp(1, mMaxWallpaperScale, 1 - zoom);
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("displayId="); pw.println(mDisplayContent.getDisplayId());
pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 42a66ad..ecbbb03 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2447,10 +2447,6 @@
// of a transaction to avoid artifacts.
win.mAnimatingExit = true;
} else {
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent.mInputMethodWindow == win) {
- displayContent.setInputMethodWindowLocked(null);
- }
boolean stopped = win.mActivityRecord != null ? win.mActivityRecord.mAppStopped : true;
// We set mDestroying=true so ActivityRecord#notifyAppStopped in-to destroy surfaces
// will later actually destroy the surface if we do not do so here. Normally we leave
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 833bb83..32eb932 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -53,6 +53,7 @@
import android.content.res.Configuration;
import android.os.Build;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArraySet;
@@ -200,6 +201,9 @@
/** Whether our process is currently running a {@link IRemoteAnimationRunner} */
private boolean mRunningRemoteAnimation;
+ /** Whether this process is owned by the System UI package. */
+ final boolean mIsSysUiPackage;
+
public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
String name, int uid, int userId, Object owner, WindowProcessListener listener) {
mInfo = info;
@@ -210,6 +214,10 @@
mListener = listener;
mAtm = atm;
mDisplayId = INVALID_DISPLAY;
+
+ mIsSysUiPackage = info.packageName.equals(
+ mAtm.getSysUiServiceComponentLocked().getPackageName());
+
onConfigurationChanged(atm.getGlobalConfiguration());
}
@@ -1077,6 +1085,12 @@
* always track the configuration of the non-finishing activity last added to the process.
*/
private void updateActivityConfigurationListener() {
+ if (mIsSysUiPackage || mUid == Process.SYSTEM_UID) {
+ // This is a system owned process and should not use an activity config.
+ // TODO(b/151161907): Remove after support for display-independent (raw) SysUi configs.
+ return;
+ }
+
for (int i = mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord activityRecord = mActivities.get(i);
if (!activityRecord.finishing && !activityRecord.containsListener(this)) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fc28cd5..c44be4d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -415,6 +415,7 @@
float mHScale=1, mVScale=1;
float mLastHScale=1, mLastVScale=1;
final Matrix mTmpMatrix = new Matrix();
+ final float[] mTmpMatrixArray = new float[9];
private final WindowFrames mWindowFrames = new WindowFrames();
@@ -446,6 +447,14 @@
float mWallpaperX = -1;
float mWallpaperY = -1;
+ // If a window showing a wallpaper: the requested zoom out for the
+ // wallpaper; if a wallpaper window: the currently applied zoom.
+ float mWallpaperZoomOut = -1;
+
+ // If a wallpaper window: whether the wallpaper should be scaled when zoomed, if set
+ // to false, mWallpaperZoom will be ignored here and just passed to the WallpaperService.
+ boolean mShouldScaleWallpaper;
+
// If a window showing a wallpaper: what fraction of the offset
// range corresponds to a full virtual screen.
float mWallpaperXStep = -1;
@@ -3923,6 +3932,9 @@
pw.println(prefix + "mWallpaperXStep=" + mWallpaperXStep
+ " mWallpaperYStep=" + mWallpaperYStep);
}
+ if (mWallpaperZoomOut != -1) {
+ pw.println(prefix + "mWallpaperZoomOut=" + mWallpaperZoomOut);
+ }
if (mWallpaperDisplayOffsetX != Integer.MIN_VALUE
|| mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
pw.println(prefix + "mWallpaperDisplayOffsetX=" + mWallpaperDisplayOffsetX
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 79dc536..563710b 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,6 +16,12 @@
package com.android.server.wm;
+import static android.graphics.Matrix.MSCALE_X;
+import static android.graphics.Matrix.MSCALE_Y;
+import static android.graphics.Matrix.MSKEW_X;
+import static android.graphics.Matrix.MSKEW_Y;
+import static android.graphics.Matrix.MTRANS_X;
+import static android.graphics.Matrix.MTRANS_Y;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
@@ -217,6 +223,10 @@
int mXOffset = 0;
int mYOffset = 0;
+ // A scale factor for the surface contents, that will be applied from the center of the visible
+ // region.
+ float mWallpaperScale = 1f;
+
/**
* A flag to determine if the WSA needs to offset its position to compensate for the stack's
* position update before the WSA surface has resized.
@@ -1034,7 +1044,12 @@
}
}
}
- mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory);
+ if (!mIsWallpaper) {
+ mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory);
+ } else {
+ setWallpaperPositionAndScale(
+ xOffset, yOffset, mWallpaperScale, recoveringMemory);
+ }
}
}
@@ -1051,11 +1066,15 @@
if (!w.mSeamlesslyRotated) {
- applyCrop(clipRect, recoveringMemory);
- mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
- mDtDx * w.mVScale * mExtraVScale,
- mDtDy * w.mHScale * mExtraHScale,
- mDsDy * w.mVScale * mExtraVScale, recoveringMemory);
+ if (!mIsWallpaper) {
+ applyCrop(clipRect, recoveringMemory);
+ mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
+ mDtDx * w.mVScale * mExtraVScale,
+ mDtDy * w.mHScale * mExtraHScale,
+ mDsDy * w.mVScale * mExtraVScale, recoveringMemory);
+ } else {
+ setWallpaperPositionAndScale(mXOffset, mYOffset, mWallpaperScale, recoveringMemory);
+ }
}
if (mSurfaceResized) {
@@ -1202,18 +1221,18 @@
mSurfaceController.setTransparentRegionHint(region);
}
- boolean setWallpaperOffset(int dx, int dy) {
- if (mXOffset == dx && mYOffset == dy) {
+ boolean setWallpaperOffset(int dx, int dy, float scale) {
+ if (mXOffset == dx && mYOffset == dy && Float.compare(mWallpaperScale, scale) == 0) {
return false;
}
mXOffset = dx;
mYOffset = dy;
+ mWallpaperScale = scale;
try {
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
mService.openSurfaceTransaction();
- mSurfaceController.setPositionInTransaction(dx, dy, false);
- applyCrop(null, false);
+ setWallpaperPositionAndScale(dx, dy, scale, false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
+ " pos=(" + dx + "," + dy + ")", e);
@@ -1225,6 +1244,27 @@
}
}
+ private void setWallpaperPositionAndScale(int dx, int dy, float scale,
+ boolean recoveringMemory) {
+ DisplayInfo displayInfo = mWin.getDisplayInfo();
+ Matrix matrix = mWin.mTmpMatrix;
+ matrix.setTranslate(dx, dy);
+ matrix.postScale(scale, scale, displayInfo.logicalWidth / 2f,
+ displayInfo.logicalHeight / 2f);
+ matrix.getValues(mWin.mTmpMatrixArray);
+ matrix.reset();
+
+ mSurfaceController.setPositionInTransaction(mWin.mTmpMatrixArray[MTRANS_X],
+ mWin.mTmpMatrixArray[MTRANS_Y], recoveringMemory);
+ mSurfaceController.setMatrixInTransaction(
+ mDsDx * mWin.mTmpMatrixArray[MSCALE_X] * mWin.mHScale * mExtraHScale,
+ mDtDx * mWin.mTmpMatrixArray[MSKEW_Y] * mWin.mVScale * mExtraVScale,
+ mDtDy * mWin.mTmpMatrixArray[MSKEW_X] * mWin.mHScale * mExtraHScale,
+ mDsDy * mWin.mTmpMatrixArray[MSCALE_Y] * mWin.mVScale * mExtraVScale,
+ recoveringMemory);
+ applyCrop(null, recoveringMemory);
+ }
+
/**
* Try to change the pixel format without recreating the surface. This
* will be common in the case of changing from PixelFormat.OPAQUE to
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 2426e8f..cccd0133 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -28,6 +28,7 @@
#include <androidfw/ZipFileRO.h>
#include <androidfw/ZipUtils.h>
#include <binder/BinderService.h>
+#include <binder/Nullable.h>
#include <binder/ParcelFileDescriptor.h>
#include <binder/Status.h>
#include <sys/stat.h>
@@ -917,19 +918,23 @@
}
bool IncrementalService::startLoading(StorageId storage) const {
- const auto ifs = getIfs(storage);
- if (!ifs) {
- return false;
- }
- std::unique_lock l(ifs->lock);
- if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) {
- if (ifs->dataLoaderReady.wait_for(l, Seconds(5)) == std::cv_status::timeout) {
- LOG(ERROR) << "Timeout waiting for data loader to be ready";
+ {
+ std::unique_lock l(mLock);
+ const auto& ifs = getIfsLocked(storage);
+ if (!ifs) {
return false;
}
+ if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) {
+ ifs->dataLoaderStartRequested = true;
+ return true;
+ }
}
+ return startDataLoader(storage);
+}
+
+bool IncrementalService::startDataLoader(MountId mountId) const {
sp<IDataLoader> dataloader;
- auto status = mDataLoaderManager->getDataLoader(ifs->mountId, &dataloader);
+ auto status = mDataLoaderManager->getDataLoader(mountId, &dataloader);
if (!status.isOk()) {
return false;
}
@@ -1065,15 +1070,9 @@
}
return true; // eventually...
}
- if (base::GetBoolProperty("incremental.skip_loader", false)) {
- LOG(INFO) << "Skipped data loader because of incremental.skip_loader property";
- std::unique_lock l(ifs.lock);
- ifs.savedDataLoaderParams.reset();
- return true;
- }
std::unique_lock l(ifs.lock);
- if (ifs.dataLoaderStatus == IDataLoaderStatusListener::DATA_LOADER_CREATED) {
+ if (ifs.dataLoaderStatus != -1) {
LOG(INFO) << "Skipped data loader preparation because it already exists";
return true;
}
@@ -1085,7 +1084,7 @@
return false;
}
FileSystemControlParcel fsControlParcel;
- fsControlParcel.incremental = std::make_unique<IncrementalFileSystemControlParcel>();
+ fsControlParcel.incremental = aidl::make_nullable<IncrementalFileSystemControlParcel>();
fsControlParcel.incremental->cmd.reset(base::unique_fd(::dup(ifs.control.cmd)));
fsControlParcel.incremental->pendingReads.reset(
base::unique_fd(::dup(ifs.control.pendingReads)));
@@ -1226,30 +1225,42 @@
externalListener->onStatusChanged(mountId, newStatus);
}
- std::unique_lock l(incrementalService.mLock);
- const auto& ifs = incrementalService.getIfsLocked(mountId);
- if (!ifs) {
- LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount "
- << mountId;
- return binder::Status::ok();
+ bool startRequested = false;
+ {
+ std::unique_lock l(incrementalService.mLock);
+ const auto& ifs = incrementalService.getIfsLocked(mountId);
+ if (!ifs) {
+ LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount "
+ << mountId;
+ return binder::Status::ok();
+ }
+ ifs->dataLoaderStatus = newStatus;
+
+ if (newStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) {
+ ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STOPPED;
+ incrementalService.deleteStorageLocked(*ifs, std::move(l));
+ return binder::Status::ok();
+ }
+
+ startRequested = ifs->dataLoaderStartRequested;
}
- ifs->dataLoaderStatus = newStatus;
+
switch (newStatus) {
case IDataLoaderStatusListener::DATA_LOADER_NO_CONNECTION: {
// TODO(b/150411019): handle data loader connection loss
break;
}
case IDataLoaderStatusListener::DATA_LOADER_CONNECTION_OK: {
- ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STARTED;
+ // TODO(b/150411019): handle data loader connection loss
break;
}
case IDataLoaderStatusListener::DATA_LOADER_CREATED: {
- ifs->dataLoaderReady.notify_one();
+ if (startRequested) {
+ incrementalService.startDataLoader(mountId);
+ }
break;
}
case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
- ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STOPPED;
- incrementalService.deleteStorageLocked(*ifs, std::move(l));
break;
}
case IDataLoaderStatusListener::DATA_LOADER_STARTED: {
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 8ff441b..406b32e 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -170,7 +170,7 @@
std::optional<DataLoaderParamsParcel> savedDataLoaderParams;
std::atomic<int> nextStorageDirNo{0};
std::atomic<int> dataLoaderStatus = -1;
- std::condition_variable dataLoaderReady;
+ bool dataLoaderStartRequested = false;
TimePoint connectionLostTime = TimePoint();
const IncrementalService& incrementalService;
@@ -208,6 +208,8 @@
bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params = nullptr,
const DataLoaderStatusListener* externalListener = nullptr);
+ bool startDataLoader(MountId mountId) const;
+
BindPathMap::const_iterator findStorageLocked(std::string_view path) const;
StorageId findStorageId(std::string_view path) const;
diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java
index 8481e5b..28e3d4b 100644
--- a/services/people/java/com/android/server/people/data/ConversationStore.java
+++ b/services/people/java/com/android/server/people/data/ConversationStore.java
@@ -89,25 +89,21 @@
* Loads conversations from disk to memory in a background thread. This should be called
* after the device powers on and the user has been unlocked.
*/
- @MainThread
- void loadConversationsFromDisk() {
- mScheduledExecutorService.execute(() -> {
- synchronized (this) {
- ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
- getConversationInfosProtoDiskReadWriter();
- if (conversationInfosProtoDiskReadWriter == null) {
- return;
- }
- List<ConversationInfo> conversationsOnDisk =
- conversationInfosProtoDiskReadWriter.read(CONVERSATIONS_FILE_NAME);
- if (conversationsOnDisk == null) {
- return;
- }
- for (ConversationInfo conversationInfo : conversationsOnDisk) {
- updateConversationsInMemory(conversationInfo);
- }
- }
- });
+ @WorkerThread
+ synchronized void loadConversationsFromDisk() {
+ ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
+ getConversationInfosProtoDiskReadWriter();
+ if (conversationInfosProtoDiskReadWriter == null) {
+ return;
+ }
+ List<ConversationInfo> conversationsOnDisk =
+ conversationInfosProtoDiskReadWriter.read(CONVERSATIONS_FILE_NAME);
+ if (conversationsOnDisk == null) {
+ return;
+ }
+ for (ConversationInfo conversationInfo : conversationsOnDisk) {
+ updateConversationsInMemory(conversationInfo);
+ }
}
/**
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 4e0afc5..7085f96 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -28,6 +28,7 @@
import android.app.prediction.AppTargetEvent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -87,13 +88,13 @@
private static final String TAG = "DataManager";
- private static final long QUERY_EVENTS_MAX_AGE_MS = DateUtils.DAY_IN_MILLIS;
+ private static final long QUERY_EVENTS_MAX_AGE_MS = 5L * DateUtils.MINUTE_IN_MILLIS;
private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L;
private final Context mContext;
private final Injector mInjector;
- private final ScheduledExecutorService mUsageStatsQueryExecutor;
- private final ScheduledExecutorService mDiskReadWriterExecutor;
+ private final ScheduledExecutorService mScheduledExecutor;
+ private final Object mLock = new Object();
private final SparseArray<UserData> mUserDataArray = new SparseArray<>();
private final SparseArray<BroadcastReceiver> mBroadcastReceivers = new SparseArray<>();
@@ -118,8 +119,7 @@
DataManager(Context context, Injector injector) {
mContext = context;
mInjector = injector;
- mUsageStatsQueryExecutor = mInjector.createScheduledExecutor();
- mDiskReadWriterExecutor = mInjector.createScheduledExecutor();
+ mScheduledExecutor = mInjector.createScheduledExecutor();
}
/** Initialization. Called when the system services are up running. */
@@ -138,103 +138,56 @@
/** This method is called when a user is unlocked. */
public void onUserUnlocked(int userId) {
- UserData userData = mUserDataArray.get(userId);
- if (userData == null) {
- userData = new UserData(userId, mDiskReadWriterExecutor);
- mUserDataArray.put(userId, userData);
+ synchronized (mLock) {
+ UserData userData = mUserDataArray.get(userId);
+ if (userData == null) {
+ userData = new UserData(userId, mScheduledExecutor);
+ mUserDataArray.put(userId, userData);
+ }
+ userData.setUserUnlocked();
}
- userData.setUserUnlocked();
- updateDefaultDialer(userData);
- updateDefaultSmsApp(userData);
-
- ScheduledFuture<?> scheduledFuture = mUsageStatsQueryExecutor.scheduleAtFixedRate(
- new UsageStatsQueryRunnable(userId), 1L, USAGE_STATS_QUERY_INTERVAL_SEC,
- TimeUnit.SECONDS);
- mUsageStatsQueryFutures.put(userId, scheduledFuture);
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED);
- intentFilter.addAction(SmsApplication.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
- BroadcastReceiver broadcastReceiver = new PerUserBroadcastReceiver(userId);
- mBroadcastReceivers.put(userId, broadcastReceiver);
- mContext.registerReceiverAsUser(
- broadcastReceiver, UserHandle.of(userId), intentFilter, null, null);
-
- ContentObserver contactsContentObserver = new ContactsContentObserver(
- BackgroundThread.getHandler());
- mContactsContentObservers.put(userId, contactsContentObserver);
- mContext.getContentResolver().registerContentObserver(
- Contacts.CONTENT_URI, /* notifyForDescendants= */ true,
- contactsContentObserver, userId);
-
- NotificationListener notificationListener = new NotificationListener();
- mNotificationListeners.put(userId, notificationListener);
- try {
- notificationListener.registerAsSystemService(mContext,
- new ComponentName(mContext, getClass()), userId);
- } catch (RemoteException e) {
- // Should never occur for local calls.
- }
-
- PackageMonitor packageMonitor = new PerUserPackageMonitor();
- packageMonitor.register(mContext, null, UserHandle.of(userId), true);
- mPackageMonitors.put(userId, packageMonitor);
-
- if (userId == UserHandle.USER_SYSTEM) {
- // The call log and MMS/SMS messages are shared across user profiles. So only need to
- // register the content observers once for the primary user.
- // TODO: Register observers after the conversations and events being loaded from disk.
- mCallLogContentObserver = new CallLogContentObserver(BackgroundThread.getHandler());
- mContext.getContentResolver().registerContentObserver(
- CallLog.CONTENT_URI, /* notifyForDescendants= */ true,
- mCallLogContentObserver, UserHandle.USER_SYSTEM);
-
- mMmsSmsContentObserver = new MmsSmsContentObserver(BackgroundThread.getHandler());
- mContext.getContentResolver().registerContentObserver(
- MmsSms.CONTENT_URI, /* notifyForDescendants= */ false,
- mMmsSmsContentObserver, UserHandle.USER_SYSTEM);
- }
-
- DataMaintenanceService.scheduleJob(mContext, userId);
+ mScheduledExecutor.execute(() -> setupUser(userId));
}
/** This method is called when a user is stopping. */
public void onUserStopping(int userId) {
- if (mUserDataArray.indexOfKey(userId) >= 0) {
- mUserDataArray.get(userId).setUserStopped();
- }
- if (mUsageStatsQueryFutures.indexOfKey(userId) >= 0) {
- mUsageStatsQueryFutures.get(userId).cancel(true);
- }
- if (mBroadcastReceivers.indexOfKey(userId) >= 0) {
- mContext.unregisterReceiver(mBroadcastReceivers.get(userId));
- }
- if (mContactsContentObservers.indexOfKey(userId) >= 0) {
- mContext.getContentResolver().unregisterContentObserver(
- mContactsContentObservers.get(userId));
- }
- if (mNotificationListeners.indexOfKey(userId) >= 0) {
- try {
- mNotificationListeners.get(userId).unregisterAsSystemService();
- } catch (RemoteException e) {
- // Should never occur for local calls.
+ synchronized (mLock) {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ if (mUserDataArray.indexOfKey(userId) >= 0) {
+ mUserDataArray.get(userId).setUserStopped();
}
- }
- if (mPackageMonitors.indexOfKey(userId) >= 0) {
- mPackageMonitors.get(userId).unregister();
- }
- if (userId == UserHandle.USER_SYSTEM) {
- if (mCallLogContentObserver != null) {
- mContext.getContentResolver().unregisterContentObserver(mCallLogContentObserver);
- mCallLogContentObserver = null;
+ if (mUsageStatsQueryFutures.indexOfKey(userId) >= 0) {
+ mUsageStatsQueryFutures.get(userId).cancel(true);
}
- if (mMmsSmsContentObserver != null) {
- mContext.getContentResolver().unregisterContentObserver(mMmsSmsContentObserver);
- mCallLogContentObserver = null;
+ if (mBroadcastReceivers.indexOfKey(userId) >= 0) {
+ mContext.unregisterReceiver(mBroadcastReceivers.get(userId));
}
- }
+ if (mContactsContentObservers.indexOfKey(userId) >= 0) {
+ contentResolver.unregisterContentObserver(mContactsContentObservers.get(userId));
+ }
+ if (mNotificationListeners.indexOfKey(userId) >= 0) {
+ try {
+ mNotificationListeners.get(userId).unregisterAsSystemService();
+ } catch (RemoteException e) {
+ // Should never occur for local calls.
+ }
+ }
+ if (mPackageMonitors.indexOfKey(userId) >= 0) {
+ mPackageMonitors.get(userId).unregister();
+ }
+ if (userId == UserHandle.USER_SYSTEM) {
+ if (mCallLogContentObserver != null) {
+ contentResolver.unregisterContentObserver(mCallLogContentObserver);
+ mCallLogContentObserver = null;
+ }
+ if (mMmsSmsContentObserver != null) {
+ contentResolver.unregisterContentObserver(mMmsSmsContentObserver);
+ mCallLogContentObserver = null;
+ }
+ }
- DataMaintenanceService.cancelJob(mContext, userId);
+ DataMaintenanceService.cancelJob(mContext, userId);
+ }
}
/**
@@ -288,6 +241,9 @@
return;
}
UserData userData = getUnlockedUserData(appTarget.getUser().getIdentifier());
+ if (userData == null) {
+ return;
+ }
PackageData packageData = userData.getOrCreatePackageData(appTarget.getPackageName());
String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
@Event.EventType int eventType = mimeTypeToShareEventType(mimeType);
@@ -353,6 +309,68 @@
userData.restore(payload);
}
+ private void setupUser(@UserIdInt int userId) {
+ synchronized (mLock) {
+ UserData userData = getUnlockedUserData(userId);
+ if (userData == null) {
+ return;
+ }
+ userData.loadUserData();
+
+ updateDefaultDialer(userData);
+ updateDefaultSmsApp(userData);
+
+ ScheduledFuture<?> scheduledFuture = mScheduledExecutor.scheduleAtFixedRate(
+ new UsageStatsQueryRunnable(userId), 1L, USAGE_STATS_QUERY_INTERVAL_SEC,
+ TimeUnit.SECONDS);
+ mUsageStatsQueryFutures.put(userId, scheduledFuture);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED);
+ intentFilter.addAction(SmsApplication.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
+ BroadcastReceiver broadcastReceiver = new PerUserBroadcastReceiver(userId);
+ mBroadcastReceivers.put(userId, broadcastReceiver);
+ mContext.registerReceiverAsUser(
+ broadcastReceiver, UserHandle.of(userId), intentFilter, null, null);
+
+ ContentObserver contactsContentObserver = new ContactsContentObserver(
+ BackgroundThread.getHandler());
+ mContactsContentObservers.put(userId, contactsContentObserver);
+ mContext.getContentResolver().registerContentObserver(
+ Contacts.CONTENT_URI, /* notifyForDescendants= */ true,
+ contactsContentObserver, userId);
+
+ NotificationListener notificationListener = new NotificationListener();
+ mNotificationListeners.put(userId, notificationListener);
+ try {
+ notificationListener.registerAsSystemService(mContext,
+ new ComponentName(mContext, getClass()), userId);
+ } catch (RemoteException e) {
+ // Should never occur for local calls.
+ }
+
+ PackageMonitor packageMonitor = new PerUserPackageMonitor();
+ packageMonitor.register(mContext, null, UserHandle.of(userId), true);
+ mPackageMonitors.put(userId, packageMonitor);
+
+ if (userId == UserHandle.USER_SYSTEM) {
+ // The call log and MMS/SMS messages are shared across user profiles. So only need
+ // to register the content observers once for the primary user.
+ mCallLogContentObserver = new CallLogContentObserver(BackgroundThread.getHandler());
+ mContext.getContentResolver().registerContentObserver(
+ CallLog.CONTENT_URI, /* notifyForDescendants= */ true,
+ mCallLogContentObserver, UserHandle.USER_SYSTEM);
+
+ mMmsSmsContentObserver = new MmsSmsContentObserver(BackgroundThread.getHandler());
+ mContext.getContentResolver().registerContentObserver(
+ MmsSms.CONTENT_URI, /* notifyForDescendants= */ false,
+ mMmsSmsContentObserver, UserHandle.USER_SYSTEM);
+ }
+
+ DataMaintenanceService.scheduleJob(mContext, userId);
+ }
+ }
+
private int mimeTypeToShareEventType(String mimeType) {
if (mimeType.startsWith("text/")) {
return Event.TYPE_SHARE_TEXT;
diff --git a/services/people/java/com/android/server/people/data/EventStore.java b/services/people/java/com/android/server/people/data/EventStore.java
index 00d4241..9cf84c9 100644
--- a/services/people/java/com/android/server/people/data/EventStore.java
+++ b/services/people/java/com/android/server/people/data/EventStore.java
@@ -17,9 +17,9 @@
package com.android.server.people.data;
import android.annotation.IntDef;
-import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.WorkerThread;
import android.net.Uri;
import android.util.ArrayMap;
@@ -90,20 +90,16 @@
* Loads existing {@link EventHistoryImpl}s from disk. This should be called when device powers
* on and user is unlocked.
*/
- @MainThread
- void loadFromDisk() {
- mScheduledExecutorService.execute(() -> {
- synchronized (this) {
- for (@EventCategory int category = 0; category < mEventsCategoryDirs.size();
- category++) {
- File categoryDir = mEventsCategoryDirs.get(category);
- Map<String, EventHistoryImpl> existingEventHistoriesImpl =
- EventHistoryImpl.eventHistoriesImplFromDisk(categoryDir,
- mScheduledExecutorService);
- mEventHistoryMaps.get(category).putAll(existingEventHistoriesImpl);
- }
- }
- });
+ @WorkerThread
+ synchronized void loadFromDisk() {
+ for (@EventCategory int category = 0; category < mEventsCategoryDirs.size();
+ category++) {
+ File categoryDir = mEventsCategoryDirs.get(category);
+ Map<String, EventHistoryImpl> existingEventHistoriesImpl =
+ EventHistoryImpl.eventHistoriesImplFromDisk(categoryDir,
+ mScheduledExecutorService);
+ mEventHistoryMaps.get(category).putAll(existingEventHistoriesImpl);
+ }
}
/**
diff --git a/services/people/java/com/android/server/people/data/MmsQueryHelper.java b/services/people/java/com/android/server/people/data/MmsQueryHelper.java
index 1e485c0..39dba9c 100644
--- a/services/people/java/com/android/server/people/data/MmsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/MmsQueryHelper.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Binder;
import android.provider.Telephony.BaseMmsColumns;
import android.provider.Telephony.Mms;
import android.telephony.PhoneNumberUtils;
@@ -71,31 +72,36 @@
// NOTE: The field Mms.DATE is stored in seconds, not milliseconds.
String[] selectionArgs = new String[] { Long.toString(sinceTime / MILLIS_PER_SECONDS) };
boolean hasResults = false;
- try (Cursor cursor = mContext.getContentResolver().query(
- Mms.CONTENT_URI, projection, selection, selectionArgs, null)) {
- if (cursor == null) {
- Slog.w(TAG, "Cursor is null when querying MMS table.");
- return false;
- }
- while (cursor.moveToNext()) {
- // ID
- int msgIdIndex = cursor.getColumnIndex(Mms._ID);
- String msgId = cursor.getString(msgIdIndex);
+ Binder.allowBlockingForCurrentThread();
+ try {
+ try (Cursor cursor = mContext.getContentResolver().query(
+ Mms.CONTENT_URI, projection, selection, selectionArgs, null)) {
+ if (cursor == null) {
+ Slog.w(TAG, "Cursor is null when querying MMS table.");
+ return false;
+ }
+ while (cursor.moveToNext()) {
+ // ID
+ int msgIdIndex = cursor.getColumnIndex(Mms._ID);
+ String msgId = cursor.getString(msgIdIndex);
- // Date
- int dateIndex = cursor.getColumnIndex(Mms.DATE);
- long date = cursor.getLong(dateIndex) * MILLIS_PER_SECONDS;
+ // Date
+ int dateIndex = cursor.getColumnIndex(Mms.DATE);
+ long date = cursor.getLong(dateIndex) * MILLIS_PER_SECONDS;
- // Message box
- int msgBoxIndex = cursor.getColumnIndex(Mms.MESSAGE_BOX);
- int msgBox = cursor.getInt(msgBoxIndex);
+ // Message box
+ int msgBoxIndex = cursor.getColumnIndex(Mms.MESSAGE_BOX);
+ int msgBox = cursor.getInt(msgBoxIndex);
- mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
- String address = getMmsAddress(msgId, msgBox);
- if (address != null && addEvent(address, date, msgBox)) {
- hasResults = true;
+ mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
+ String address = getMmsAddress(msgId, msgBox);
+ if (address != null && addEvent(address, date, msgBox)) {
+ hasResults = true;
+ }
}
}
+ } finally {
+ Binder.defaultBlockingForCurrentThread();
}
return hasResults;
}
diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java
index 3e4c992..28837d5 100644
--- a/services/people/java/com/android/server/people/data/PackageData.java
+++ b/services/people/java/com/android/server/people/data/PackageData.java
@@ -25,6 +25,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.annotation.WorkerThread;
import android.content.LocusId;
import android.os.FileUtils;
import android.text.TextUtils;
@@ -77,6 +78,7 @@
* Returns a map of package directory names as keys and their associated {@link PackageData}.
* This should be called when device is powered on and unlocked.
*/
+ @WorkerThread
@NonNull
static Map<String, PackageData> packagesDataFromDisk(@UserIdInt int userId,
@NonNull Predicate<String> isDefaultDialerPredicate,
diff --git a/services/people/java/com/android/server/people/data/SmsQueryHelper.java b/services/people/java/com/android/server/people/data/SmsQueryHelper.java
index c38c846..a5eb3a5 100644
--- a/services/people/java/com/android/server/people/data/SmsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/SmsQueryHelper.java
@@ -19,6 +19,7 @@
import android.annotation.WorkerThread;
import android.content.Context;
import android.database.Cursor;
+import android.os.Binder;
import android.provider.Telephony.Sms;
import android.provider.Telephony.TextBasedSmsColumns;
import android.telephony.PhoneNumberUtils;
@@ -65,35 +66,40 @@
String selection = Sms.DATE + " > ?";
String[] selectionArgs = new String[] { Long.toString(sinceTime) };
boolean hasResults = false;
- try (Cursor cursor = mContext.getContentResolver().query(
- Sms.CONTENT_URI, projection, selection, selectionArgs, null)) {
- if (cursor == null) {
- Slog.w(TAG, "Cursor is null when querying SMS table.");
- return false;
- }
- while (cursor.moveToNext()) {
- // ID
- int msgIdIndex = cursor.getColumnIndex(Sms._ID);
- String msgId = cursor.getString(msgIdIndex);
+ Binder.allowBlockingForCurrentThread();
+ try {
+ try (Cursor cursor = mContext.getContentResolver().query(
+ Sms.CONTENT_URI, projection, selection, selectionArgs, null)) {
+ if (cursor == null) {
+ Slog.w(TAG, "Cursor is null when querying SMS table.");
+ return false;
+ }
+ while (cursor.moveToNext()) {
+ // ID
+ int msgIdIndex = cursor.getColumnIndex(Sms._ID);
+ String msgId = cursor.getString(msgIdIndex);
- // Date
- int dateIndex = cursor.getColumnIndex(Sms.DATE);
- long date = cursor.getLong(dateIndex);
+ // Date
+ int dateIndex = cursor.getColumnIndex(Sms.DATE);
+ long date = cursor.getLong(dateIndex);
- // Type
- int typeIndex = cursor.getColumnIndex(Sms.TYPE);
- int type = cursor.getInt(typeIndex);
+ // Type
+ int typeIndex = cursor.getColumnIndex(Sms.TYPE);
+ int type = cursor.getInt(typeIndex);
- // Address
- int addressIndex = cursor.getColumnIndex(Sms.ADDRESS);
- String address = PhoneNumberUtils.formatNumberToE164(
- cursor.getString(addressIndex), mCurrentCountryIso);
+ // Address
+ int addressIndex = cursor.getColumnIndex(Sms.ADDRESS);
+ String address = PhoneNumberUtils.formatNumberToE164(
+ cursor.getString(addressIndex), mCurrentCountryIso);
- mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
- if (address != null && addEvent(address, date, type)) {
- hasResults = true;
+ mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
+ if (address != null && addEvent(address, date, type)) {
+ hasResults = true;
+ }
}
}
+ } finally {
+ Binder.defaultBlockingForCurrentThread();
}
return hasResults;
}
diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java
index ed8c595..429d5b7 100644
--- a/services/people/java/com/android/server/people/data/UserData.java
+++ b/services/people/java/com/android/server/people/data/UserData.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.annotation.WorkerThread;
import android.os.Environment;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -75,12 +76,6 @@
void setUserUnlocked() {
mIsUnlocked = true;
-
- // Ensures per user root directory for people data is present, and attempt to load
- // data from disk.
- mPerUserPeopleDataDir.mkdirs();
- mPackageDataMap.putAll(PackageData.packagesDataFromDisk(mUserId, this::isDefaultDialer,
- this::isDefaultSmsApp, mScheduledExecutorService, mPerUserPeopleDataDir));
}
void setUserStopped() {
@@ -91,6 +86,15 @@
return mIsUnlocked;
}
+ @WorkerThread
+ void loadUserData() {
+ mPerUserPeopleDataDir.mkdir();
+ Map<String, PackageData> packageDataMap = PackageData.packagesDataFromDisk(
+ mUserId, this::isDefaultDialer, this::isDefaultSmsApp, mScheduledExecutorService,
+ mPerUserPeopleDataDir);
+ mPackageDataMap.putAll(packageDataMap);
+ }
+
/**
* Gets the {@link PackageData} for the specified {@code packageName} if exists; otherwise
* creates a new instance and returns it.
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 95f4e83..c45ee7b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -55,6 +55,7 @@
import android.text.TextUtils;
import android.util.Pair;
+import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.appop.AppOpsService;
import com.android.server.wm.ActivityTaskManagerService;
@@ -125,6 +126,8 @@
mAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
mAms.mAtmInternal = spy(mAms.mActivityTaskManager.getAtmInternal());
mAms.mPackageManagerInt = mPackageManagerInt;
+ doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
}
@After
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index fc2ae40..fe42dc9 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -75,8 +75,10 @@
import android.app.IApplicationThread;
import android.app.IServiceConnection;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.IBinder;
@@ -87,6 +89,7 @@
import android.util.ArraySet;
import android.util.SparseArray;
+import com.android.server.LocalServices;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.wm.WindowProcessController;
@@ -127,6 +130,7 @@
private static final String MOCKAPP5_PROCESSNAME = "test #5";
private static final String MOCKAPP5_PACKAGENAME = "com.android.test.test5";
private static Context sContext;
+ private static PackageManagerInternal sPackageManagerInternal;
private static ActivityManagerService sService;
@BeforeClass
@@ -134,9 +138,15 @@
sContext = getInstrumentation().getTargetContext();
System.setProperty("dexmaker.share_classloader", "true");
+ sPackageManagerInternal = mock(PackageManagerInternal.class);
+ doReturn(new ComponentName("", "")).when(sPackageManagerInternal)
+ .getSystemUiServiceComponent();
+ LocalServices.addService(PackageManagerInternal.class, sPackageManagerInternal);
+
sService = mock(ActivityManagerService.class);
sService.mActivityTaskManager = new ActivityTaskManagerService(sContext);
sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper());
+ sService.mPackageManagerInt = sPackageManagerInternal;
sService.mAtmInternal = spy(sService.mActivityTaskManager.getAtmInternal());
sService.mConstants = new ActivityManagerConstants(sContext, sService,
@@ -972,7 +982,7 @@
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doReturn(null).when(sService).getTopAppLocked();
- assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
+ assertProcStates(app, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index eb2dd64..2944643 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -267,6 +267,49 @@
}
@Test
+ public void testEnableTargetSdkChangesForPackage() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1L)
+ .addDisabledChangeWithId(2L)
+ .addTargetSdkChangeWithId(3, 3L)
+ .addTargetSdkChangeWithId(4, 4L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("foo.bar")
+ .withTargetSdk(2)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
+
+ assertThat(compatConfig.enableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
+ assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
+ }
+
+ @Test
+ public void testDisableTargetSdkChangesForPackage() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1L)
+ .addDisabledChangeWithId(2L)
+ .addTargetSdkChangeWithId(3, 3L)
+ .addTargetSdkChangeWithId(4, 4L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("foo.bar")
+ .withTargetSdk(2)
+ .build();
+
+ assertThat(compatConfig.enableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
+ assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
+
+ assertThat(compatConfig.disableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
+ assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
+ }
+
+ @Test
public void testLookupChangeId() throws Exception {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addEnabledChangeWithIdAndName(1234L, "MY_CHANGE")
diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
index b0def60..ccbaee4 100644
--- a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
@@ -18,6 +18,11 @@
import static android.hardware.lights.LightsRequest.Builder;
+import static android.graphics.Color.BLACK;
+import static android.graphics.Color.BLUE;
+import static android.graphics.Color.GREEN;
+import static android.graphics.Color.WHITE;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
@@ -92,7 +97,7 @@
// When the session requests to turn 3/4 lights on:
LightsManager.LightsSession session = manager.openSession();
- session.setLights(new Builder()
+ session.requestLights(new Builder()
.setLight(manager.getLights().get(0), new LightState(0xf1))
.setLight(manager.getLights().get(1), new LightState(0xf2))
.setLight(manager.getLights().get(2), new LightState(0xf3))
@@ -114,18 +119,18 @@
Light micLight = manager.getLights().get(0);
// The light should begin by being off.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLACK);
// When a session commits changes:
LightsManager.LightsSession session = manager.openSession();
- session.setLights(new Builder().setLight(micLight, new LightState(0xff00ff00)).build());
+ session.requestLights(new Builder().setLight(micLight, new LightState(GREEN)).build());
// Then the light should turn on.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff00ff00);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(GREEN);
// When the session goes away:
session.close();
// Then the light should turn off.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLACK);
}
@Test
@@ -138,15 +143,15 @@
LightsManager.LightsSession session2 = manager.openSession();
// When session1 and session2 both request the same light:
- session1.setLights(new Builder().setLight(micLight, new LightState(0xff0000ff)).build());
- session2.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+ session1.requestLights(new Builder().setLight(micLight, new LightState(BLUE)).build());
+ session2.requestLights(new Builder().setLight(micLight, new LightState(WHITE)).build());
// Then session1 should win because it was created first.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff0000ff);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLUE);
// When session1 goes away:
session1.close();
// Then session2 should have its request go into effect.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xffffffff);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(WHITE);
// When session2 goes away:
session2.close();
@@ -162,10 +167,10 @@
// When the session turns a light on:
LightsManager.LightsSession session = manager.openSession();
- session.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+ session.requestLights(new Builder().setLight(micLight, new LightState(WHITE)).build());
// And then the session clears it again:
- session.setLights(new Builder().clearLight(micLight).build());
+ session.requestLights(new Builder().clearLight(micLight).build());
// Then the light should turn back off.
assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
index 4e63237..e10cbbf 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
@@ -273,9 +273,8 @@
// Ensure that futures were cancelled and the immediate flush occurred.
assertEquals(0, mMockScheduledExecutorService.getFutures().size());
- // Expect to see 2 executes: loadConversationFromDisk and saveConversationsToDisk.
- // loadConversationFromDisk gets called each time we call #resetConversationStore().
- assertEquals(2, mMockScheduledExecutorService.getExecutes().size());
+ // Expect to see 1 execute: saveConversationsToDisk.
+ assertEquals(1, mMockScheduledExecutorService.getExecutes().size());
resetConversationStore();
ConversationInfo out1 = mConversationStore.getConversation(SHORTCUT_ID);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index a4d63ac..5199604 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -183,6 +183,11 @@
when(mExecutorService.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(
TimeUnit.class))).thenReturn(mScheduledFuture);
+ doAnswer(ans -> {
+ Runnable runnable = (Runnable) ans.getArguments()[0];
+ runnable.run();
+ return null;
+ }).when(mExecutorService).execute(any(Runnable.class));
when(mUserManager.getEnabledProfiles(USER_ID_PRIMARY))
.thenReturn(Arrays.asList(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 049c8e1..6eec649 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.START_ABORTED;
+import static android.app.ActivityManager.START_CANCELED;
import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
@@ -202,10 +203,11 @@
final IApplicationThread caller = mock(IApplicationThread.class);
final WindowProcessListener listener = mock(WindowProcessListener.class);
+ final ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = "com.android.test.package";
final WindowProcessController wpc =
containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
- ? null : new WindowProcessController(
- service, mock(ApplicationInfo.class), null, 0, -1, null, listener);
+ ? null : new WindowProcessController(service, ai, null, 0, -1, null, listener);
doReturn(wpc).when(service).getProcessController(anyObject());
final Intent intent = new Intent();
@@ -344,6 +346,7 @@
doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(),
anyInt(), anyBoolean(), anyInt());
+ doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent();
// Never review permissions
doReturn(false).when(mMockPackageManager).isPermissionsReviewRequired(any(), anyInt());
@@ -655,6 +658,7 @@
final WindowProcessListener listener = mock(WindowProcessListener.class);
final ApplicationInfo ai = new ApplicationInfo();
ai.uid = callingUid;
+ ai.packageName = "com.android.test.package";
final WindowProcessController callerApp =
new WindowProcessController(mService, ai, null, callingUid, -1, null, listener);
callerApp.setHasForegroundActivities(hasForegroundActivities);
@@ -892,7 +896,7 @@
.execute();
// Simulate a failed start
- starter.postStartActivityProcessing(null, START_ABORTED, null);
+ starter.postStartActivityProcessing(null, START_CANCELED, null);
verify(recentTasks, times(1)).setFreezeTaskListReordering();
verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
@@ -1019,7 +1023,7 @@
public void taskAppeared(ActivityManager.RunningTaskInfo info) {
}
@Override
- public void taskVanished(IWindowContainer wc) {
+ public void taskVanished(ActivityManager.RunningTaskInfo info) {
}
@Override
public void transactionReady(int id, SurfaceControl.Transaction t) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index 5cf1fbb..a380ece 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -69,7 +71,7 @@
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
- assertNotNull(getController().getInsetsForDispatch(app).getSource(ITYPE_STATUS_BAR));
+ assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
}
@Test
@@ -101,6 +103,34 @@
}
@Test
+ public void testStripForDispatch_pip() {
+ final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
+ final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+ getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
+ getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+ app.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
+ }
+
+ @Test
+ public void testStripForDispatch_freeform() {
+ final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
+ final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+ getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
+ getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+ app.setWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
+ }
+
+ @Test
public void testImeForDispatch() {
final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
final WindowState ime = createWindow(null, TYPE_APPLICATION, "ime");
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index ac4c228f..12d89de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -131,6 +131,7 @@
LocalServices.addService(PackageManagerInternal.class, mMockPmi);
when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(
Collections.singletonList(TEST_COMPONENT.getPackageName()), /* observer */ null));
+ when(mMockPmi.getSystemUiServiceComponent()).thenReturn(new ComponentName("", ""));
mTarget.onSystemReady();
final ArgumentCaptor<PackageManagerInternal.PackageListObserver> observerCaptor =
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 55d12db..560d03f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -40,6 +40,7 @@
import android.app.AppOpsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IntentFilter;
@@ -213,6 +214,9 @@
anyString(), anyInt());
doReturn(null).when(packageManagerInternal).getDefaultHomeActivity(anyInt());
+ ComponentName systemServiceComponent = new ComponentName("android.test.system.service", "");
+ doReturn(systemServiceComponent).when(packageManagerInternal).getSystemUiServiceComponent();
+
// PowerManagerInternal
final PowerManagerInternal pmi = mock(PowerManagerInternal.class);
final PowerSaveState state = new PowerSaveState.Builder().build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index a1f1412..251886a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -129,7 +129,7 @@
final Task task = createTaskInStack(stack, 0 /* userId */);
final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
-
+
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
verify(organizer).taskAppeared(any());
stack.setWindowingMode(WINDOWING_MODE_PINNED);
@@ -371,7 +371,7 @@
public void taskAppeared(RunningTaskInfo taskInfo) { }
@Override
- public void taskVanished(IWindowContainer container) { }
+ public void taskVanished(RunningTaskInfo container) { }
@Override
public void transactionReady(int id, SurfaceControl.Transaction t) { }
@@ -425,7 +425,7 @@
public void taskAppeared(RunningTaskInfo taskInfo) { }
@Override
- public void taskVanished(IWindowContainer container) { }
+ public void taskVanished(RunningTaskInfo container) { }
@Override
public void transactionReady(int id, SurfaceControl.Transaction t) { }
@@ -565,7 +565,7 @@
mInfo = info;
}
@Override
- public void taskVanished(IWindowContainer wc) {
+ public void taskVanished(RunningTaskInfo info) {
}
@Override
public void transactionReady(int id, SurfaceControl.Transaction t) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index e1475a4..91c3c27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -77,7 +77,8 @@
}
@Override
- public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync)
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom,
+ boolean sync)
throws RemoteException {
}
@@ -85,7 +86,6 @@
public void dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras,
boolean sync) throws RemoteException {
}
-
@Override
public void dispatchDragEvent(DragEvent event) throws RemoteException {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index aa66524..900f014 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -17,19 +17,29 @@
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
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.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
import android.view.Gravity;
@@ -139,4 +149,124 @@
assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getConfiguration().orientation);
assertEquals(portraitFrame, wallpaperWindow.getFrameLw());
}
+
+ @Test
+ public void testWallpaperZoom() throws RemoteException {
+ final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, dc, true /* ownerCanManageAppTokens */);
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
+ "wallpaperWindow");
+ wallpaperWindow.getAttrs().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
+
+ final WindowState homeWindow = createWallpaperTargetWindow(dc);
+
+ spyOn(dc.mWallpaperController);
+ doReturn(true).when(dc.mWallpaperController).isWallpaperVisible();
+
+ dc.mWallpaperController.adjustWallpaperWindows();
+
+ spyOn(wallpaperWindow.mClient);
+
+ float zoom = .5f;
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, zoom);
+ assertEquals(zoom, wallpaperWindow.mWallpaperZoomOut, .01f);
+ verify(wallpaperWindow.mClient).dispatchWallpaperOffsets(anyFloat(), anyFloat(), anyFloat(),
+ anyFloat(), eq(zoom), anyBoolean());
+ }
+
+ @Test
+ public void testWallpaperZoom_shouldNotScaleWallpaper() throws RemoteException {
+ final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, dc, true /* ownerCanManageAppTokens */);
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
+ "wallpaperWindow");
+ wallpaperWindow.getAttrs().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
+
+ final WindowState homeWindow = createWallpaperTargetWindow(dc);
+
+ spyOn(dc.mWallpaperController);
+ doReturn(true).when(dc.mWallpaperController).isWallpaperVisible();
+
+ dc.mWallpaperController.adjustWallpaperWindows();
+
+ spyOn(wallpaperWindow.mClient);
+
+ float newZoom = .5f;
+ wallpaperWindow.mShouldScaleWallpaper = false;
+ // Set zoom, and make sure the window animator scale didn't actually change, but the zoom
+ // value did, and we do dispatch the zoom to the wallpaper service
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, newZoom);
+ assertEquals(newZoom, wallpaperWindow.mWallpaperZoomOut, .01f);
+ assertEquals(1f, wallpaperWindow.mWinAnimator.mWallpaperScale, .01f);
+ verify(wallpaperWindow.mClient).dispatchWallpaperOffsets(anyFloat(), anyFloat(), anyFloat(),
+ anyFloat(), eq(newZoom), anyBoolean());
+ }
+
+ @Test
+ public void testWallpaperZoom_multipleCallers() {
+ final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, dc,
+ true /* ownerCanManageAppTokens */);
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
+ "wallpaperWindow");
+ wallpaperWindow.getAttrs().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
+
+
+ spyOn(dc.mWallpaperController);
+ doReturn(true).when(dc.mWallpaperController).isWallpaperVisible();
+
+ final WindowState homeWindow = createWallpaperTargetWindow(dc);
+
+ WindowState otherWindow = createWindow(null /* parent */, TYPE_APPLICATION, dc,
+ "otherWindow");
+
+ dc.mWallpaperController.adjustWallpaperWindows();
+
+ spyOn(wallpaperWindow.mClient);
+
+ // Set zoom from 2 windows
+ float homeWindowInitialZoom = .5f;
+ float otherWindowInitialZoom = .7f;
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, homeWindowInitialZoom);
+ dc.mWallpaperController.setWallpaperZoomOut(otherWindow, otherWindowInitialZoom);
+ // Make sure the largest one wins
+ assertEquals(otherWindowInitialZoom, wallpaperWindow.mWallpaperZoomOut, .01f);
+
+ // Change zoom to a larger zoom from homeWindow
+ float homeWindowZoom2 = .8f;
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, homeWindowZoom2);
+ // New zoom should be current
+ assertEquals(homeWindowZoom2, wallpaperWindow.mWallpaperZoomOut, .01f);
+
+ // Set homeWindow zoom to a lower zoom, but keep the one from otherWindow
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, homeWindowInitialZoom);
+
+ // Zoom from otherWindow should be the current.
+ assertEquals(otherWindowInitialZoom, wallpaperWindow.mWallpaperZoomOut, .01f);
+ }
+
+
+ private WindowState createWallpaperTargetWindow(DisplayContent dc) {
+ final ActivityRecord homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(dc.getRootHomeTask())
+ .setCreateTask(true)
+ .build();
+ homeActivity.setVisibility(true);
+
+ WindowState appWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
+ homeActivity, "wallpaperTargetWindow");
+ appWindow.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+ appWindow.mHasSurface = true;
+ spyOn(appWindow);
+ doReturn(true).when(appWindow).isDrawFinishedLw();
+
+ homeActivity.addWindow(appWindow);
+ return appWindow;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 34e487b..07a6179 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -29,6 +29,7 @@
import static org.mockito.Mockito.when;
import android.app.IApplicationThread;
+import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
@@ -55,8 +56,11 @@
@Before
public void setUp() {
mMockListener = mock(WindowProcessListener.class);
+
+ ApplicationInfo info = mock(ApplicationInfo.class);
+ info.packageName = "test.package.name";
mWpc = new WindowProcessController(
- mService, mock(ApplicationInfo.class), null, 0, -1, null, mMockListener);
+ mService, info, null, 0, -1, null, mMockListener);
mWpc.setThread(mock(IApplicationThread.class));
}
@@ -176,6 +180,26 @@
assertEquals(mWpc.getLastReportedConfiguration(), newConfig);
}
+ @Test
+ public void testActivityNotOverridingSystemUiProcessConfig() {
+ final ComponentName systemUiServiceComponent = mService.getSysUiServiceComponentLocked();
+ ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
+ applicationInfo.packageName = systemUiServiceComponent.getPackageName();
+
+ WindowProcessController wpc = new WindowProcessController(
+ mService, applicationInfo, null, 0, -1, null, mMockListener);
+ wpc.setThread(mock(IApplicationThread.class));
+
+ final ActivityRecord activity = new ActivityBuilder(mService)
+ .setCreateTask(true)
+ .setUseProcess(wpc)
+ .build();
+
+ wpc.addActivityIfNeeded(activity);
+ // System UI owned processes should not be registered for activity config changes.
+ assertFalse(wpc.registeredForActivityConfigChanges());
+ }
+
private TestDisplayContent createTestDisplayContentInContainer() {
return new TestDisplayContent.Builder(mService, 1000, 1500).build();
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
index af81ab6..be0987d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
@@ -257,6 +257,9 @@
int userHandle) {
SQLiteDatabase db = getReadableDatabase();
Cursor c = db.rawQuery(selectQuery, null);
+ if (DBG) {
+ Slog.w(TAG, "querying database: " + selectQuery);
+ }
try {
if (c.moveToFirst()) {
@@ -334,7 +337,10 @@
return model;
} while (c.moveToNext());
}
- Slog.w(TAG, "No SoundModel available for the given keyphrase");
+
+ if (DBG) {
+ Slog.w(TAG, "No SoundModel available for the given keyphrase");
+ }
} finally {
c.close();
db.close();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 0b24dd2..0eba07b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -41,6 +41,7 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
import android.hardware.soundtrigger.KeyphraseMetadata;
import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
@@ -223,6 +224,7 @@
class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
VoiceInteractionManagerServiceImpl mImpl;
+ KeyphraseEnrollmentInfo mEnrollmentApplicationInfo;
private boolean mSafeMode;
private int mCurUser;
@@ -447,6 +449,15 @@
}
}
+ private void getOrCreateEnrollmentApplicationInfo() {
+ synchronized (this) {
+ if (mEnrollmentApplicationInfo == null) {
+ mEnrollmentApplicationInfo = new KeyphraseEnrollmentInfo(
+ mContext.getPackageManager());
+ }
+ }
+ }
+
private void setCurrentUserLocked(@UserIdInt int userHandle) {
mCurUser = userHandle;
final UserInfo userInfo = mUserManagerInternal.getUserInfo(mCurUser);
@@ -1380,12 +1391,17 @@
pw.println(" mCurUserUnlocked: " + mCurUserUnlocked);
pw.println(" mCurUserSupported: " + mCurUserSupported);
dumpSupportedUsers(pw, " ");
+ if (mEnrollmentApplicationInfo == null) {
+ pw.println(" (No enrollment application info)");
+ } else {
+ pw.println(" " + mEnrollmentApplicationInfo.toString());
+ }
mDbHelper.dump(pw);
if (mImpl == null) {
pw.println(" (No active implementation)");
- return;
+ } else {
+ mImpl.dumpLocked(fd, pw, args);
}
- mImpl.dumpLocked(fd, pw, args);
}
mSoundTriggerInternal.dump(fd, pw, args);
}
@@ -1438,8 +1454,9 @@
}
private boolean isCallerTrustedEnrollmentApplication() {
- return mImpl.mEnrollmentApplicationInfo.isUidSupportedEnrollmentApplication(
- Binder.getCallingUid());
+ getOrCreateEnrollmentApplicationInfo();
+ return mEnrollmentApplicationInfo.isUidSupportedEnrollmentApplication(
+ Binder.getCallingUid());
}
private void setImplLocked(VoiceInteractionManagerServiceImpl impl) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index b813f87..a62b03c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -36,7 +36,6 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -79,7 +78,6 @@
final IActivityManager mAm;
final IActivityTaskManager mAtm;
final VoiceInteractionServiceInfo mInfo;
- final KeyphraseEnrollmentInfo mEnrollmentApplicationInfo;
final ComponentName mSessionComponentName;
final IWindowManager mIWindowManager;
boolean mBound = false;
@@ -135,7 +133,6 @@
mComponent = service;
mAm = ActivityManager.getService();
mAtm = ActivityTaskManager.getService();
- mEnrollmentApplicationInfo = new KeyphraseEnrollmentInfo(context.getPackageManager());
VoiceInteractionServiceInfo info;
try {
info = new VoiceInteractionServiceInfo(context.getPackageManager(), service, mUser);
@@ -406,7 +403,6 @@
pw.println(" Active session:");
mActiveSession.dump(" ", pw);
}
- pw.println(" " + mEnrollmentApplicationInfo.toString());
}
void startLocked() {
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index 36c6377..c832f53 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -38,16 +38,14 @@
*
* <p>
* Below is an example manifest registration for a {@code CallRedirectionService}.
- * <pre>
* {@code
* <service android:name="your.package.YourCallRedirectionServiceImplementation"
- * android:permission="android.permission.BIND_REDIRECTION_SERVICE">
+ * android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
* <intent-filter>
* <action android:name="android.telecom.CallRedirectionService"/>
* </intent-filter>
* </service>
* }
- * </pre>
*/
public abstract class CallRedirectionService extends Service {
/**
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 0093843..bebbbd0 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -80,17 +80,20 @@
* Reason code (returned via {@link #getReason()}) which indicates that a call could not be
* completed because the cellular radio is off or out of service, the device is connected to
* a wifi network, but the user has not enabled wifi calling.
+ * @hide
*/
public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
/**
* Reason code (returned via {@link #getReason()}), which indicates that the video telephony
* call was disconnected because IMS access is blocked.
+ * @hide
*/
public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
/**
* Reason code, which indicates that the conference call is simulating single party conference.
+ * @hide
*/
public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 4e6e1a5..768c8ee 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -53,7 +53,6 @@
* {@link android.telecom.ConnectionService}.
* @hide
*/
- @SystemApi
public static final String EXTRA_SORT_ORDER =
"android.telecom.extra.SORT_ORDER";
@@ -89,7 +88,6 @@
* rather than cellular calls.
* @hide
*/
- @SystemApi
public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE =
"android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
@@ -114,7 +112,6 @@
*
* @hide
*/
- @SystemApi
public static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK =
"android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK";
@@ -163,7 +160,6 @@
* in progress.
* @hide
*/
- @SystemApi
public static final String EXTRA_PLAY_CALL_RECORDING_TONE =
"android.telecom.extra.PLAY_CALL_RECORDING_TONE";
@@ -258,7 +254,6 @@
* See {@link #getCapabilities}
* @hide
*/
- @SystemApi
public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80;
/**
@@ -282,7 +277,6 @@
* convert all outgoing video calls to emergency numbers to audio-only.
* @hide
*/
- @SystemApi
public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
/**
@@ -340,7 +334,6 @@
*
* @hide
*/
- @SystemApi
public static final int CAPABILITY_EMERGENCY_PREFERRED = 0x2000;
/**
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 7f4fcc0..2761127 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -318,13 +318,13 @@
* the remote handle of the new call.
* @hide
*/
- @SystemApi
public static final String EXTRA_UNKNOWN_CALL_HANDLE =
"android.telecom.extra.UNKNOWN_CALL_HANDLE";
/**
* Optional extra for incoming and outgoing calls containing a long which specifies the time the
* call was created. This value is in milliseconds since boot.
+ * @hide
*/
public static final String EXTRA_CALL_CREATED_TIME_MILLIS =
"android.telecom.extra.CALL_CREATED_TIME_MILLIS";
@@ -388,7 +388,6 @@
* </ul>
* @hide
*/
- @SystemApi
public static final String EXTRA_CALL_TECHNOLOGY_TYPE =
"android.telecom.extra.CALL_TECHNOLOGY_TYPE";
@@ -731,7 +730,6 @@
* @see #EXTRA_CURRENT_TTY_MODE
* @hide
*/
- @SystemApi
public static final String ACTION_CURRENT_TTY_MODE_CHANGED =
"android.telecom.action.CURRENT_TTY_MODE_CHANGED";
@@ -746,7 +744,6 @@
* </ul>
* @hide
*/
- @SystemApi
public static final String EXTRA_CURRENT_TTY_MODE =
"android.telecom.extra.CURRENT_TTY_MODE";
@@ -757,7 +754,6 @@
* @see #EXTRA_TTY_PREFERRED_MODE
* @hide
*/
- @SystemApi
public static final String ACTION_TTY_PREFERRED_MODE_CHANGED =
"android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
@@ -768,7 +764,6 @@
*
* @hide
*/
- @SystemApi
public static final String EXTRA_TTY_PREFERRED_MODE =
"android.telecom.extra.TTY_PREFERRED_MODE";
@@ -846,7 +841,6 @@
*
* @hide
*/
- @SystemApi
public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
/**
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 9ae86c8..dcd4eb5 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -1,7 +1,6 @@
package android.telephony;
import android.annotation.IntDef;
-import android.provider.Telephony;
import android.telecom.Connection;
import android.telephony.data.ApnSetting;
@@ -653,15 +652,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface UiccAppType{}
- /** @hide */
- @IntDef({
- Telephony.Carriers.SKIP_464XLAT_DEFAULT,
- Telephony.Carriers.SKIP_464XLAT_DISABLE,
- Telephony.Carriers.SKIP_464XLAT_ENABLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Skip464XlatStatus {}
-
/**
* Override network type
*/
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 2d31d95..c20748b 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1568,6 +1568,7 @@
/**
* The string is used to compare with operator name.
* If it matches the pattern then show specific data icon.
+ * @hide
*/
public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING =
"show_carrier_data_icon_pattern_string";
@@ -2978,9 +2979,9 @@
* UE wants to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise not
* define.
* The configuration is: "connected_mmwave:5G_Plus,connected:5G"
+ * @hide
*/
- public static final String KEY_5G_ICON_CONFIGURATION_STRING =
- "5g_icon_configuration_string";
+ public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string";
/**
* Timeout in seconds for displaying 5G icon, default value is 0 which means the timer is
@@ -2992,12 +2993,14 @@
*
* If 5G is reacquired during this timer, the timer is canceled and restarted when 5G is next
* lost. Allows us to momentarily lose 5G without blinking the icon.
+ * @hide
*/
public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT =
"5g_icon_display_grace_period_sec_int";
/**
* Controls time in milliseconds until DcTracker reevaluates 5G connection state.
+ * @hide
*/
public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long";
@@ -3527,6 +3530,15 @@
"support_wps_over_ims_bool";
/**
+ * The two digital number pattern of MMI code which is defined by carrier.
+ * If the dial number matches this pattern, it will be dialed out normally not USSD.
+ *
+ * @hide
+ */
+ public static final String KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY =
+ "mmi_two_digit_number_pattern_string_array";
+
+ /**
* Holds the list of carrier certificate hashes.
* Note that each carrier has its own certificates.
*/
@@ -4083,6 +4095,7 @@
new int[] {4 /* BUSY */});
sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false);
sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000);
+ sDefaults.putStringArray(KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY, new String[0]);
sDefaults.putInt(KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
CellSignalStrengthLte.USE_RSRP);
// Default wifi configurations.
diff --git a/telephony/java/android/telephony/CdmaEriInformation.java b/telephony/java/android/telephony/CdmaEriInformation.java
index 1cd9d30..fd0b905 100644
--- a/telephony/java/android/telephony/CdmaEriInformation.java
+++ b/telephony/java/android/telephony/CdmaEriInformation.java
@@ -40,7 +40,6 @@
*
* @hide
*/
-@SystemApi
public final class CdmaEriInformation implements Parcelable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 270eafe..c667165 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -208,7 +208,6 @@
* @return {@code true} if using carrier aggregation.
* @hide
*/
- @SystemApi
public boolean isUsingCarrierAggregation() {
return mIsUsingCarrierAggregation;
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c74e17f..1a79bf7 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -367,6 +367,7 @@
* Get the 5G NR connection state.
*
* @return the 5G NR connection state.
+ * @hide
*/
public @NRState int getNrState() {
return mNrState;
diff --git a/telephony/java/android/telephony/PinResult.java b/telephony/java/android/telephony/PinResult.java
index c14bd91..98d6448 100644
--- a/telephony/java/android/telephony/PinResult.java
+++ b/telephony/java/android/telephony/PinResult.java
@@ -19,7 +19,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,7 +31,6 @@
*
* @hide
*/
-@SystemApi
public final class PinResult implements Parcelable {
/** @hide */
@IntDef({
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 9b1baef..dd20d06 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -580,7 +580,6 @@
*
* @hide
*/
- @SystemApi
public @RegState int getDataRegistrationState() {
return getDataRegState();
}
@@ -689,8 +688,9 @@
* @return true if registration indicates roaming, false otherwise
* @hide
*/
- @SystemApi
public boolean getDataRoamingFromRegistration() {
+ // TODO: all callers should refactor to get roaming state directly from modem
+ // this should not be exposed as a public API
return mIsDataRoamingFromRegistration;
}
@@ -1422,7 +1422,6 @@
* @return the frequency range of 5G NR.
* @hide
*/
- @SystemApi
public @FrequencyRange int getNrFrequencyRange() {
return mNrFrequencyRange;
}
@@ -2026,6 +2025,7 @@
* The long format can be up to 16 characters long.
*
* @return long raw name of operator, null if unregistered or unknown
+ * @hide
*/
@Nullable
public String getOperatorAlphaLongRaw() {
@@ -2045,6 +2045,7 @@
* The short format can be up to 8 characters long.
*
* @return short raw name of operator, null if unregistered or unknown
+ * @hide
*/
@Nullable
public String getOperatorAlphaShortRaw() {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 8ac9023b..5a840de 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1300,8 +1300,13 @@
* both active and hidden SubscriptionInfos.
*
*/
- public @Nullable List<SubscriptionInfo> getActiveAndHiddenSubscriptionInfoList() {
- return getActiveSubscriptionInfoList(/* userVisibleonly */false);
+ public @NonNull List<SubscriptionInfo> getCompleteActiveSubscriptionInfoList() {
+ List<SubscriptionInfo> completeList = getActiveSubscriptionInfoList(
+ /* userVisibleonly */false);
+ if (completeList == null) {
+ completeList = new ArrayList<>();
+ }
+ return completeList;
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3c40e35..db5a047 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -2371,7 +2371,12 @@
public static final int PHONE_TYPE_CDMA = PhoneConstants.PHONE_TYPE_CDMA;
/** Phone is via SIP. */
public static final int PHONE_TYPE_SIP = PhoneConstants.PHONE_TYPE_SIP;
- /** Phone is via IMS. */
+
+ /**
+ * Phone is via IMS.
+ *
+ * @hide
+ */
public static final int PHONE_TYPE_IMS = PhoneConstants.PHONE_TYPE_IMS;
/**
@@ -2379,7 +2384,6 @@
*
* @hide
*/
- @SystemApi
public static final int PHONE_TYPE_THIRD_PARTY = PhoneConstants.PHONE_TYPE_THIRD_PARTY;
/**
@@ -3763,29 +3767,6 @@
}
/**
- * Returns the ISO-3166 country code equivalent for the SIM provider's country code
- * of the default subscription
- * <p>
- * The ISO-3166 country code is provided in lowercase 2 character format.
- * @return the lowercase 2 character ISO-3166 country code, or empty string is not available.
- * <p>
- * Note: This API is introduced to unblock mainlining work as the following APIs in
- * Linkify.java invokes getSimCountryIso() without a context. TODO(Bug 144576376): remove
- * this API once the following APIs are redesigned to access telephonymanager with a context.
- *
- * {@link Linkify#addLinks(@NonNull Spannable text, @LinkifyMask int mask)}
- * {@link Linkify#addLinks(@NonNull Spannable text, @LinkifyMask int mask,
- @Nullable Function<String, URLSpan> urlSpanFactory)}
- *
- * @hide
- */
- @SystemApi
- @NonNull
- public static String getDefaultSimCountryIso() {
- return getSimCountryIso(SubscriptionManager.getDefaultSubscriptionId());
- }
-
- /**
* Returns the ISO country code equivalent for the SIM provider's country code.
*
* @param subId for which SimCountryIso is returned
@@ -5606,7 +5587,6 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- @SystemApi
@NonNull
public CdmaEriInformation getCdmaEriInformation() {
return new CdmaEriInformation(
@@ -8726,7 +8706,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public PinResult supplyPinReportPinResult(@NonNull String pin) {
@@ -8751,7 +8730,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public PinResult supplyPukReportPinResult(@NonNull String puk, @NonNull String pin) {
@@ -12236,12 +12214,14 @@
/**
* It indicates whether modem is enabled or not per slot.
- * It's the corresponding status of {@link #enableModemForSlot}.
+ * It's the corresponding status of TelephonyManager.enableModemForSlot.
*
+ * <p>Requires Permission:
+ * READ_PRIVILEGED_PHONE_STATE or
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @param slotIndex which slot it's checking.
- * @hide
*/
- @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public boolean isModemEnabledForSlot(int slotIndex) {
try {
ITelephony telephony = getITelephony();
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index f5dfacc6..bfb54b0 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -18,7 +18,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.content.ContentValues;
import android.database.Cursor;
import android.hardware.radio.V1_5.ApnTypes;
@@ -27,7 +26,6 @@
import android.os.Parcelable;
import android.provider.Telephony;
import android.provider.Telephony.Carriers;
-import android.telephony.Annotation;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.NetworkType;
import android.telephony.ServiceState;
@@ -126,6 +124,15 @@
/** Authentication type for PAP or CHAP. */
public static final int AUTH_TYPE_PAP_OR_CHAP = 3;
+ /** @hide */
+ @IntDef({
+ Telephony.Carriers.SKIP_464XLAT_DEFAULT,
+ Telephony.Carriers.SKIP_464XLAT_DISABLE,
+ Telephony.Carriers.SKIP_464XLAT_ENABLE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Skip464XlatStatus {}
+
/**
* APN types for data connections. These are usage categories for an APN
* entry. One APN entry may support multiple APN types, eg, a single APN
@@ -139,7 +146,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_ALL_STRING = "*";
/**
@@ -147,7 +153,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_DEFAULT_STRING = "default";
@@ -156,7 +161,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_MMS_STRING = "mms";
@@ -165,7 +169,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_SUPL_STRING = "supl";
/**
@@ -173,7 +176,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_DUN_STRING = "dun";
/**
@@ -181,7 +183,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_HIPRI_STRING = "hipri";
/**
@@ -189,7 +190,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_FOTA_STRING = "fota";
/**
@@ -197,7 +197,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_IMS_STRING = "ims";
/**
@@ -205,7 +204,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_CBS_STRING = "cbs";
/**
@@ -213,7 +211,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_IA_STRING = "ia";
/**
@@ -222,7 +219,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_EMERGENCY_STRING = "emergency";
/**
@@ -230,7 +226,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_MCX_STRING = "mcx";
/**
@@ -238,7 +233,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_XCAP_STRING = "xcap";
@@ -745,7 +739,7 @@
* @return SKIP_464XLAT_DEFAULT, SKIP_464XLAT_DISABLE or SKIP_464XLAT_ENABLE
* @hide
*/
- @Annotation.Skip464XlatStatus
+ @Skip464XlatStatus
public int getSkip464Xlat() {
return mSkip464Xlat;
}
@@ -1416,7 +1410,6 @@
* @return comma delimited list of APN types.
* @hide
*/
- @SystemApi
@NonNull
public static String getApnTypesStringFromBitmask(int apnTypeBitmask) {
List<String> types = new ArrayList<>();
@@ -2065,7 +2058,7 @@
* @param skip464xlat skip464xlat for this APN.
* @hide
*/
- public Builder setSkip464Xlat(@Annotation.Skip464XlatStatus int skip464xlat) {
+ public Builder setSkip464Xlat(@Skip464XlatStatus int skip464xlat) {
this.mSkip464Xlat = skip464xlat;
return this;
}
diff --git a/telephony/java/android/telephony/ims/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index 025721c..81af99f 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -58,7 +58,7 @@
try {
mListener.callSessionProgressing(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -71,7 +71,7 @@
try {
mListener.callSessionInitiated(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -85,7 +85,7 @@
try {
mListener.callSessionInitiatedFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -98,7 +98,7 @@
try {
mListener.callSessionTerminated(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -115,7 +115,7 @@
try {
mListener.callSessionHeld(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -128,7 +128,7 @@
try {
mListener.callSessionHoldFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -141,7 +141,7 @@
try {
mListener.callSessionHoldReceived(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -155,7 +155,7 @@
try {
mListener.callSessionResumed(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -169,7 +169,7 @@
try {
mListener.callSessionResumeFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -182,7 +182,7 @@
try {
mListener.callSessionResumeReceived(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -201,7 +201,7 @@
mListener.callSessionMergeStarted(newSession != null ?
newSession.getServiceImpl() : null, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -216,7 +216,7 @@
try {
mListener.callSessionMergeStarted(newSession, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -232,7 +232,7 @@
mListener.callSessionMergeComplete(newSession != null ?
newSession.getServiceImpl() : null);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -247,7 +247,7 @@
try {
mListener.callSessionMergeComplete(newSession);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -260,7 +260,7 @@
try {
mListener.callSessionMergeFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -273,7 +273,7 @@
try {
mListener.callSessionUpdated(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -286,7 +286,7 @@
try {
mListener.callSessionUpdateFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -299,7 +299,7 @@
try {
mListener.callSessionUpdateReceived(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -319,7 +319,7 @@
mListener.callSessionConferenceExtended(
newSession != null ? newSession.getServiceImpl() : null, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -333,7 +333,7 @@
try {
mListener.callSessionConferenceExtended(newSession, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -347,7 +347,7 @@
try {
mListener.callSessionConferenceExtendFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -364,7 +364,7 @@
mListener.callSessionConferenceExtendReceived(newSession != null
? newSession.getServiceImpl() : null, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -379,7 +379,7 @@
try {
mListener.callSessionConferenceExtendReceived(newSession, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -391,7 +391,7 @@
try {
mListener.callSessionInviteParticipantsRequestDelivered();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -407,7 +407,7 @@
try {
mListener.callSessionInviteParticipantsRequestFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -419,7 +419,7 @@
try {
mListener.callSessionRemoveParticipantsRequestDelivered();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -435,7 +435,7 @@
try {
mListener.callSessionInviteParticipantsRequestFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -448,7 +448,7 @@
try {
mListener.callSessionConferenceStateUpdated(state);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -465,7 +465,7 @@
try {
mListener.callSessionUssdMessageReceived(mode, ussdMessage);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -501,7 +501,7 @@
try {
mListener.callSessionMayHandover(srcNetworkType, targetNetworkType);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -537,7 +537,7 @@
try {
mListener.callSessionHandover(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -570,7 +570,7 @@
try {
mListener.callSessionHandoverFailed(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -587,7 +587,7 @@
try {
mListener.callSessionTtyModeReceived(mode);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -600,7 +600,7 @@
try {
mListener.callSessionMultipartyStateChanged(isMultiParty);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -614,7 +614,7 @@
try {
mListener.callSessionSuppServiceReceived(suppSrvNotification);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -628,7 +628,7 @@
try {
mListener.callSessionRttModifyRequestReceived(callProfile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -641,7 +641,7 @@
try {
mListener.callSessionRttModifyResponseReceived(status);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -654,7 +654,7 @@
try {
mListener.callSessionRttMessageReceived(rttMessage);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -667,7 +667,7 @@
try {
mListener.callSessionRttAudioIndicatorChanged(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -680,7 +680,7 @@
try {
mListener.callQualityChanged(callQuality);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 3341fa7..4b5303f 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -294,8 +294,15 @@
throw new IllegalArgumentException("Must include a non-null Executor.");
}
c.setExecutor(executor);
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
try {
- getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
+ iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -331,8 +338,15 @@
throw new IllegalArgumentException("Must include a non-null Executor.");
}
c.setExecutor(executor);
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
try {
- getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
+ iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
} catch (ServiceSpecificException e) {
throw new ImsException(e.getMessage(), e.errorCode);
} catch (RemoteException | IllegalStateException e) {
@@ -361,8 +375,14 @@
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().unregisterImsRegistrationCallback(mSubId, c.getBinder());
+ iTelephony.unregisterImsRegistrationCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -387,8 +407,14 @@
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().unregisterImsRegistrationCallback(mSubId, c.getBinder());
+ iTelephony.unregisterImsRegistrationCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -409,8 +435,14 @@
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().getImsMmTelRegistrationState(mSubId, new IIntegerConsumer.Stub() {
+ iTelephony.getImsMmTelRegistrationState(mSubId, new IIntegerConsumer.Stub() {
@Override
public void accept(int result) {
executor.execute(() -> stateCallback.accept(result));
@@ -443,8 +475,14 @@
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().getImsMmTelRegistrationTransportType(mSubId,
+ iTelephony.getImsMmTelRegistrationTransportType(mSubId,
new IIntegerConsumer.Stub() {
@Override
public void accept(int result) {
@@ -506,8 +544,15 @@
throw new IllegalArgumentException("Must include a non-null Executor.");
}
c.setExecutor(executor);
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_INVALID_SUBSCRIPTION);
+ }
+
try {
- getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
+ iTelephony.registerMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -553,8 +598,14 @@
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
+ iTelephony.unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -599,8 +650,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isAdvancedCallingSettingEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isAdvancedCallingSettingEnabled(mSubId);
+ return iTelephony.isAdvancedCallingSettingEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -640,8 +696,13 @@
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi @TestApi
public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setAdvancedCallingSettingEnabled(mSubId, isEnabled);
+ iTelephony.setAdvancedCallingSettingEnabled(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -680,8 +741,13 @@
@SystemApi @TestApi
public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isCapable(mSubId, capability, imsRegTech);
+ return iTelephony.isCapable(mSubId, capability, imsRegTech);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -709,8 +775,13 @@
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isAvailable(mSubId, capability, imsRegTech);
+ return iTelephony.isAvailable(mSubId, capability, imsRegTech);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -744,6 +815,13 @@
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
try {
getITelephony().isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
@Override
@@ -788,8 +866,13 @@
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
public boolean isVtSettingEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isVtSettingEnabled(mSubId);
+ return iTelephony.isVtSettingEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -813,8 +896,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVtSettingEnabled(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVtSettingEnabled(mSubId, isEnabled);
+ iTelephony.setVtSettingEnabled(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -853,8 +941,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isVoWiFiSettingEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isVoWiFiSettingEnabled(mSubId);
+ return iTelephony.isVoWiFiSettingEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -879,8 +972,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiSettingEnabled(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiSettingEnabled(mSubId, isEnabled);
+ iTelephony.setVoWiFiSettingEnabled(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -921,8 +1019,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isVoWiFiRoamingSettingEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId);
+ return iTelephony.isVoWiFiRoamingSettingEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -948,8 +1051,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
+ iTelephony.setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -980,8 +1088,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiNonPersistent(mSubId, isCapable, mode);
+ iTelephony.setVoWiFiNonPersistent(mSubId, isCapable, mode);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1025,8 +1138,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public @WiFiCallingMode int getVoWiFiModeSetting() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().getVoWiFiModeSetting(mSubId);
+ return iTelephony.getVoWiFiModeSetting(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1054,8 +1172,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiModeSetting(mSubId, mode);
+ iTelephony.setVoWiFiModeSetting(mSubId, mode);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1085,8 +1208,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().getVoWiFiRoamingModeSetting(mSubId);
+ return iTelephony.getVoWiFiRoamingModeSetting(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1116,8 +1244,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiRoamingModeSetting(mSubId, mode);
+ iTelephony.setVoWiFiRoamingModeSetting(mSubId, mode);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1145,8 +1278,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setRttCapabilitySetting(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setRttCapabilitySetting(mSubId, isEnabled);
+ iTelephony.setRttCapabilitySetting(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1186,8 +1324,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isTtyOverVolteEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isTtyOverVolteEnabled(mSubId);
+ return iTelephony.isTtyOverVolteEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1223,8 +1366,15 @@
if (callback == null) {
throw new IllegalArgumentException("Must include a non-null Consumer.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
try {
- getITelephony().getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
+ iTelephony.getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
@Override
public void accept(int result) {
executor.execute(() -> callback.accept(result));
@@ -1243,9 +1393,6 @@
.getTelephonyServiceManager()
.getTelephonyServiceRegisterer()
.get());
- if (binder == null) {
- throw new RuntimeException("Could not find Telephony Service.");
- }
return binder;
}
}
diff --git a/test-mock/src/android/test/mock/MockContentResolver.java b/test-mock/src/android/test/mock/MockContentResolver.java
index 8283019..8f4bccc 100644
--- a/test-mock/src/android/test/mock/MockContentResolver.java
+++ b/test-mock/src/android/test/mock/MockContentResolver.java
@@ -25,6 +25,7 @@
import android.database.ContentObserver;
import android.net.Uri;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -172,7 +173,7 @@
* from observers elsewhere in the system.
*/
@Override
- public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+ public void notifyChange(@NonNull Collection<Uri> uris, @Nullable ContentObserver observer,
@NotifyFlags int flags) {
}
}
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index 8f7bebb..6eb4587 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -139,7 +139,7 @@
mTaskView2.reparentTask(ti.token);
}
}
- public void taskVanished(IWindowContainer wc) {
+ public void taskVanished(ActivityManager.RunningTaskInfo ti) {
}
public void transactionReady(int id, SurfaceControl.Transaction t) {
mergedTransaction.merge(t);
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index bd17751..ade5c2e 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -49,7 +49,7 @@
} catch (Exception e) {
}
}
- public void taskVanished(IWindowContainer wc) {
+ public void taskVanished(ActivityManager.RunningTaskInfo ti) {
}
public void transactionReady(int id, SurfaceControl.Transaction t) {
}
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
index 8e6f198..e415170 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
@@ -16,11 +16,15 @@
package com.google.android.test.windowinsetstests;
+import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
import static java.lang.Math.max;
import static java.lang.Math.min;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -37,6 +41,8 @@
import android.view.WindowInsetsAnimation.Callback;
import android.view.WindowInsetsAnimationControlListener;
import android.view.WindowInsetsAnimationController;
+import android.view.WindowInsetsController;
+import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
@@ -82,8 +88,8 @@
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDown = event.getY();
- mDownInsets = v.getRootWindowInsets().getInsets(Type.ime());
- mShownAtDown = v.getRootWindowInsets().isVisible(Type.ime());
+ mDownInsets = v.getRootWindowInsets().getInsets(ime());
+ mShownAtDown = v.getRootWindowInsets().isVisible(ime());
mRequestedController = false;
mCurrentRequest = null;
break;
@@ -94,7 +100,7 @@
> mViewConfiguration.getScaledTouchSlop()
&& !mRequestedController) {
mRequestedController = true;
- v.getWindowInsetsController().controlWindowInsetsAnimation(Type.ime(),
+ v.getWindowInsetsController().controlWindowInsetsAnimation(ime(),
1000, new LinearInterpolator(),
mCurrentRequest = new WindowInsetsAnimationControlListener() {
@Override
@@ -189,6 +195,51 @@
getWindow().getDecorView().post(() -> getWindow().setDecorFitsSystemWindows(false));
}
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getWindow().getInsetsController().addOnControllableInsetsChangedListener(
+ new OnControllableInsetsChangedListener() {
+
+ boolean hasControl = false;
+ @Override
+ public void onControllableInsetsChanged(WindowInsetsController controller,
+ int types) {
+ if ((types & ime()) != 0 && !hasControl) {
+ hasControl = true;
+ controller.controlWindowInsetsAnimation(ime(), -1,
+ new LinearInterpolator(),
+ new WindowInsetsAnimationControlListener() {
+ @Override
+ public void onReady(
+ WindowInsetsAnimationController controller,
+ int types) {
+ ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+ anim.setDuration(1500);
+ anim.addUpdateListener(animation
+ -> controller.setInsetsAndAlpha(
+ controller.getShownStateInsets(),
+ (float) animation.getAnimatedValue(),
+ anim.getAnimatedFraction()));
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ controller.finish(true);
+ }
+ });
+ anim.start();
+ }
+
+ @Override
+ public void onCancelled() {
+ }
+ });
+ }
+ }
+ });
+ }
+
static class Transition {
private int mEndBottom;
private int mStartBottom;
@@ -200,7 +251,7 @@
}
void onPrepare(WindowInsetsAnimation animation) {
- if ((animation.getTypeMask() & Type.ime()) != 0) {
+ if ((animation.getTypeMask() & ime()) != 0) {
mInsetsAnimation = animation;
}
mStartBottom = mView.getBottom();
diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
index fe51b3a..1658262 100644
--- a/tests/net/common/java/android/net/RouteInfoTest.java
+++ b/tests/net/common/java/android/net/RouteInfoTest.java
@@ -19,19 +19,40 @@
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
+import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
-import junit.framework.TestCase;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
-public class RouteInfoTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RouteInfoTest {
+ @Rule
+ public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
+ private static final int INVALID_ROUTE_TYPE = -1;
private InetAddress Address(String addr) {
return InetAddress.parseNumericAddress(addr);
@@ -41,15 +62,32 @@
return new IpPrefix(prefix);
}
- @SmallTest
+ @Test
public void testConstructor() {
RouteInfo r;
-
// Invalid input.
try {
r = new RouteInfo((IpPrefix) null, null, "rmnet0");
fail("Expected RuntimeException: destination and gateway null");
- } catch(RuntimeException e) {}
+ } catch (RuntimeException e) { }
+
+ try {
+ r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "rmnet0",
+ INVALID_ROUTE_TYPE);
+ fail("Invalid route type should cause exception");
+ } catch (IllegalArgumentException e) { }
+
+ try {
+ r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("192.0.2.1"), "rmnet0",
+ RTN_UNREACHABLE);
+ fail("Address family mismatch should cause exception");
+ } catch (IllegalArgumentException e) { }
+
+ try {
+ r = new RouteInfo(Prefix("0.0.0.0/0"), Address("2001:db8::1"), "rmnet0",
+ RTN_UNREACHABLE);
+ fail("Address family mismatch should cause exception");
+ } catch (IllegalArgumentException e) { }
// Null destination is default route.
r = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), null);
@@ -74,6 +112,7 @@
assertNull(r.getInterface());
}
+ @Test
public void testMatches() {
class PatchedRouteInfo {
private final RouteInfo mRouteInfo;
@@ -113,6 +152,7 @@
assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
}
+ @Test
public void testEquals() {
// IPv4
RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
@@ -146,6 +186,7 @@
assertNotEqualEitherWay(r1, r3);
}
+ @Test
public void testHostAndDefaultRoutes() {
RouteInfo r;
@@ -228,6 +269,7 @@
assertFalse(r.isIPv6Default());
}
+ @Test
public void testTruncation() {
LinkAddress l;
RouteInfo r;
@@ -244,6 +286,7 @@
// Make sure that creating routes to multicast addresses doesn't throw an exception. Even though
// there's nothing we can do with them, we don't want to crash if, e.g., someone calls
// requestRouteToHostAddress("230.0.0.0", MOBILE_HIPRI);
+ @Test
public void testMulticastRoute() {
RouteInfo r;
r = new RouteInfo(Prefix("230.0.0.0/32"), Address("192.0.2.1"), "wlan0");
@@ -251,16 +294,36 @@
// No exceptions? Good.
}
+ @Test
public void testParceling() {
RouteInfo r;
-
- r = new RouteInfo(Prefix("::/0"), Address("2001:db8::"), null);
+ r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), null);
assertParcelingIsLossless(r);
-
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
- assertParcelSane(r, 7);
+ assertParcelingIsLossless(r);
+ r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0", RTN_UNREACHABLE);
+ assertParcelingIsLossless(r);
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testMtuParceling() {
+ final RouteInfo r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::"), "testiface",
+ RTN_UNREACHABLE, 1450 /* mtu */);
+ assertParcelingIsLossless(r);
+ }
+
+ @Test @IgnoreAfter(Build.VERSION_CODES.Q)
+ public void testFieldCount_Q() {
+ assertFieldCountEquals(6, RouteInfo.class);
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testFieldCount() {
+ // Make sure any new field is covered by the above parceling tests when changing this number
+ assertFieldCountEquals(7, RouteInfo.class);
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testMtu() {
RouteInfo r;
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0",
diff --git a/tests/net/common/java/android/net/util/SocketUtilsTest.kt b/tests/net/common/java/android/net/util/SocketUtilsTest.kt
index 9c7cfb0..aaf97f3 100644
--- a/tests/net/common/java/android/net/util/SocketUtilsTest.kt
+++ b/tests/net/common/java/android/net/util/SocketUtilsTest.kt
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package android.net.util;
+package android.net.util
+import android.os.Build
import android.system.NetlinkSocketAddress
import android.system.Os
import android.system.OsConstants.AF_INET
@@ -26,18 +27,26 @@
import android.system.PacketSocketAddress
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
private const val TEST_INDEX = 123
private const val TEST_PORT = 555
+private const val FF_BYTE = 0xff.toByte()
+
@RunWith(AndroidJUnit4::class)
@SmallTest
class SocketUtilsTest {
+ @Rule @JvmField
+ val ignoreRule = DevSdkIgnoreRule()
+
@Test
fun testMakeNetlinkSocketAddress() {
val nlAddress = SocketUtils.makeNetlinkSocketAddress(TEST_PORT, RTMGRP_NEIGH)
@@ -50,16 +59,21 @@
}
@Test
- fun testMakePacketSocketAddress() {
+ fun testMakePacketSocketAddress_Q() {
val pkAddress = SocketUtils.makePacketSocketAddress(ETH_P_ALL, TEST_INDEX)
assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
- val ff = 0xff.toByte()
- val pkAddress2 = SocketUtils.makePacketSocketAddress(TEST_INDEX,
- byteArrayOf(ff, ff, ff, ff, ff, ff))
+ val pkAddress2 = SocketUtils.makePacketSocketAddress(TEST_INDEX, ByteArray(6) { FF_BYTE })
assertTrue("Not PacketSocketAddress object", pkAddress2 is PacketSocketAddress)
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ fun testMakePacketSocketAddress() {
+ val pkAddress = SocketUtils.makePacketSocketAddress(
+ ETH_P_ALL, TEST_INDEX, ByteArray(6) { FF_BYTE })
+ assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
+ }
+
@Test
fun testCloseSocket() {
// Expect no exception happening with null object.
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index a9e0b9a..36deca3 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -64,6 +64,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
import android.app.AlarmManager;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
@@ -163,7 +164,6 @@
private @Mock IBinder mBinder;
private @Mock AlarmManager mAlarmManager;
private HandlerThread mHandlerThread;
- private Handler mHandler;
private NetworkStatsService mService;
private INetworkStatsSession mSession;
@@ -192,15 +192,11 @@
PowerManager.WakeLock wakeLock =
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mService = new NetworkStatsService(
- mServiceContext, mNetManager, mAlarmManager, wakeLock, mClock,
- mServiceContext.getSystemService(TelephonyManager.class), mSettings,
- mStatsFactory, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir));
mHandlerThread = new HandlerThread("HandlerThread");
- mHandlerThread.start();
- Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService);
- mHandler = new Handler(mHandlerThread.getLooper(), callback);
- mService.setHandler(mHandler, callback);
+ final NetworkStatsService.Dependencies deps = makeDependencies();
+ mService = new NetworkStatsService(mServiceContext, mNetManager, mAlarmManager, wakeLock,
+ mClock, mServiceContext.getSystemService(TelephonyManager.class), mSettings,
+ mStatsFactory, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir), deps);
mElapsedRealtime = 0L;
@@ -217,11 +213,21 @@
// catch INetworkManagementEventObserver during systemReady()
ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
- ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
+ ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
verify(mNetManager).registerObserver(networkObserver.capture());
mNetworkObserver = networkObserver.getValue();
}
+ @NonNull
+ private NetworkStatsService.Dependencies makeDependencies() {
+ return new NetworkStatsService.Dependencies() {
+ @Override
+ public HandlerThread makeHandlerThread() {
+ return mHandlerThread;
+ }
+ };
+ }
+
@After
public void tearDown() throws Exception {
IoUtils.deleteContents(mStatsDir);
@@ -234,6 +240,8 @@
mSession.close();
mService = null;
+
+ mHandlerThread.quitSafely();
}
@Test
@@ -939,9 +947,7 @@
long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
assertEquals(minThresholdInBytes, request.thresholdInBytes);
- // Send dummy message to make sure that any previous message has been handled
- mHandler.sendMessage(mHandler.obtainMessage(-1));
- HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
+ HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
// Make sure that the caller binder gets connected
verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
@@ -1077,7 +1083,7 @@
// Simulates alert quota of the provider has been reached.
cb.onAlertReached();
- HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
+ HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
// Verifies that polling is triggered by alert reached.
provider.expectStatsUpdate(0 /* unused */);
@@ -1294,9 +1300,7 @@
private void forcePollAndWaitForIdle() {
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
- // Send dummy message to make sure that any previous message has been handled
- mHandler.sendMessage(mHandler.obtainMessage(-1));
- HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
+ HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
}
static class LatchedHandler extends Handler {
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index cbf6fe8..b1e2487 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -120,12 +120,6 @@
"liblog",
"libcutils",
],
- apex_available: [
- "//apex_available:platform",
- //TODO(b/149781190): Remove this once statsd no longer depends on libstatslog
- "com.android.os.statsd",
- "test_com.android.os.statsd",
- ],
target: {
android: {
shared_libs: ["libstatssocket"],
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 91174d3..f4d2881 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -177,14 +177,14 @@
java_library {
name: "framework-wifi-stubs-publicapi",
srcs: [":framework-wifi-stubs-srcs-publicapi"],
- sdk_version: "module_current",
+ sdk_version: "current",
installable: false,
}
java_library {
name: "framework-wifi-stubs-systemapi",
srcs: [":framework-wifi-stubs-srcs-systemapi"],
- sdk_version: "module_current",
+ sdk_version: "system_current",
libs: ["framework-annotations-lib"],
installable: false,
}
diff --git a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
similarity index 82%
rename from wifi/java/android/net/wifi/IScoreChangeCallback.aidl
rename to wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
index d691f41..775fed7 100644
--- a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
+++ b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
@@ -21,9 +21,9 @@
*
* @hide
*/
-oneway interface IScoreChangeCallback
+oneway interface IScoreUpdateObserver
{
- void onScoreChange(int sessionId, int score);
+ void notifyScoreUpdate(int sessionId, int score);
- void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
+ void triggerUpdateOfWifiUsabilityStats(int sessionId);
}
diff --git a/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
index d9a3b01..f96d037 100644
--- a/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
+++ b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
@@ -16,7 +16,7 @@
package android.net.wifi;
-import android.net.wifi.IScoreChangeCallback;
+import android.net.wifi.IScoreUpdateObserver;
/**
* Interface for Wi-Fi connected network scorer.
@@ -25,9 +25,9 @@
*/
oneway interface IWifiConnectedNetworkScorer
{
- void start(int sessionId);
+ void onStart(int sessionId);
- void stop(int sessionId);
+ void onStop(int sessionId);
- void setScoreChangeCallback(IScoreChangeCallback cbImpl);
+ void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl);
}
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 2b47623..a269e17 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -35,7 +35,6 @@
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@@ -211,7 +210,7 @@
* Delay in milliseconds before shutting down soft AP when
* there are no connected devices.
*/
- private final int mShutdownTimeoutMillis;
+ private final long mShutdownTimeoutMillis;
/**
* THe definition of security type OPEN.
@@ -247,7 +246,7 @@
private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
@Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel,
@SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled,
- int shutdownTimeoutMillis, boolean clientControlByUser,
+ long shutdownTimeoutMillis, boolean clientControlByUser,
@NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList) {
mSsid = ssid;
mBssid = bssid;
@@ -327,7 +326,7 @@
dest.writeInt(mSecurityType);
dest.writeInt(mMaxNumberOfClients);
dest.writeBoolean(mAutoShutdownEnabled);
- dest.writeInt(mShutdownTimeoutMillis);
+ dest.writeLong(mShutdownTimeoutMillis);
dest.writeBoolean(mClientControlByUser);
dest.writeTypedList(mBlockedClientList);
dest.writeTypedList(mAllowedClientList);
@@ -346,7 +345,7 @@
in.readString(),
in.readParcelable(MacAddress.class.getClassLoader()),
in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(),
- in.readInt(), in.readBoolean(), in.readInt(), in.readBoolean(),
+ in.readInt(), in.readBoolean(), in.readLong(), in.readBoolean(),
in.createTypedArrayList(MacAddress.CREATOR),
in.createTypedArrayList(MacAddress.CREATOR));
}
@@ -454,19 +453,19 @@
/**
* Returns the shutdown timeout in milliseconds.
* The Soft AP will shutdown when there are no devices associated to it for
- * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(int)}.
+ * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(long)}.
*
* @hide
*/
@SystemApi
- public int getShutdownTimeoutMillis() {
+ public long getShutdownTimeoutMillis() {
return mShutdownTimeoutMillis;
}
/**
* Returns a flag indicating whether clients need to be pre-approved by the user.
* (true: authorization required) or not (false: not required).
- * {@link Builder#enableClientControlByUser(Boolean)}.
+ * {@link Builder#setClientControlByUserEnabled(Boolean)}.
*
* @hide
*/
@@ -478,7 +477,7 @@
/**
* Returns List of clients which aren't allowed to associate to the AP.
*
- * Clients are configured using {@link Builder#setClientList(List, List)}
+ * Clients are configured using {@link Builder#setBlockedClientList(List)}
*
* @hide
*/
@@ -490,7 +489,7 @@
/**
* List of clients which are allowed to associate to the AP.
- * Clients are configured using {@link Builder#setClientList(List, List)}
+ * Clients are configured using {@link Builder#setAllowedClientList(List)}
*
* @hide
*/
@@ -575,7 +574,7 @@
private int mMaxNumberOfClients;
private int mSecurityType;
private boolean mAutoShutdownEnabled;
- private int mShutdownTimeoutMillis;
+ private long mShutdownTimeoutMillis;
private boolean mClientControlByUser;
private List<MacAddress> mBlockedClientList;
private List<MacAddress> mAllowedClientList;
@@ -627,6 +626,11 @@
*/
@NonNull
public SoftApConfiguration build() {
+ for (MacAddress client : mAllowedClientList) {
+ if (mBlockedClientList.contains(client)) {
+ throw new IllegalArgumentException("A MacAddress exist in both client list");
+ }
+ }
return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients,
mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser,
@@ -835,7 +839,7 @@
* @param enable true to enable, false to disable.
* @return Builder for chaining.
*
- * @see #setShutdownTimeoutMillis(int)
+ * @see #setShutdownTimeoutMillis(long)
*/
@NonNull
public Builder setAutoShutdownEnabled(boolean enable) {
@@ -862,7 +866,7 @@
* @see #setAutoShutdownEnabled(boolean)
*/
@NonNull
- public Builder setShutdownTimeoutMillis(@IntRange(from = 0) int timeoutMillis) {
+ public Builder setShutdownTimeoutMillis(@IntRange(from = 0) long timeoutMillis) {
if (timeoutMillis < 0) {
throw new IllegalArgumentException("Invalid timeout value");
}
@@ -878,7 +882,7 @@
*
* If manual user control is enabled then clients will be accepted, rejected, or require
* a user approval based on the configuration provided by
- * {@link #setClientList(List, List)}.
+ * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}.
*
* <p>
* This method requires hardware support. Hardware support can be determined using
@@ -898,26 +902,48 @@
* @return Builder for chaining.
*/
@NonNull
- public Builder enableClientControlByUser(boolean enabled) {
+ public Builder setClientControlByUserEnabled(boolean enabled) {
mClientControlByUser = enabled;
return this;
}
/**
- * This method together with {@link enableClientControlByUser(boolean)} control client
- * connections to the AP. If {@link enableClientControlByUser(false)} is configured than
+ * This method together with {@link setClientControlByUserEnabled(boolean)} control client
+ * connections to the AP. If client control by user is disabled using the above method then
* this API has no effect and clients are allowed to associate to the AP (within limit of
* max number of clients).
*
- * If {@link enableClientControlByUser(true)} is configured then this API configures
- * 2 lists:
+ * If client control by user is enabled then this API configures the list of clients
+ * which are explicitly allowed. These are auto-accepted.
+ *
+ * All other clients which attempt to associate, whose MAC addresses are on neither list,
+ * are:
* <ul>
- * <li>List of clients which are blocked. These are rejected.</li>
- * <li>List of clients which are explicitly allowed. These are auto-accepted.</li>
+ * <li>Rejected</li>
+ * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)}
+ * is issued (which allows the user to add them to the allowed client list if desired).<li>
* </ul>
*
- * <p>
+ * @param allowedClientList list of clients which are allowed to associate to the AP
+ * without user pre-approval.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) {
+ mAllowedClientList = new ArrayList<>(allowedClientList);
+ return this;
+ }
+
+ /**
+ * This method together with {@link setClientControlByUserEnabled(boolean)} control client
+ * connections to the AP. If client control by user is disabled using the above method then
+ * this API has no effect and clients are allowed to associate to the AP (within limit of
+ * max number of clients).
+ *
+ * If client control by user is enabled then this API this API configures the list of
+ * clients which are blocked. These are rejected.
+ *
* All other clients which attempt to associate, whose MAC addresses are on neither list,
* are:
* <ul>
@@ -927,23 +953,11 @@
* </ul>
*
* @param blockedClientList list of clients which are not allowed to associate to the AP.
- * @param allowedClientList list of clients which are allowed to associate to the AP
- * without user pre-approval.
* @return Builder for chaining.
*/
@NonNull
- public Builder setClientList(@NonNull List<MacAddress> blockedClientList,
- @NonNull List<MacAddress> allowedClientList) {
+ public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) {
mBlockedClientList = new ArrayList<>(blockedClientList);
- mAllowedClientList = new ArrayList<>(allowedClientList);
- Iterator<MacAddress> iterator = mAllowedClientList.iterator();
- while (iterator.hasNext()) {
- MacAddress client = iterator.next();
- int index = mBlockedClientList.indexOf(client);
- if (index != -1) {
- throw new IllegalArgumentException("A MacAddress exist in both list");
- }
- }
return this;
}
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ceb2907..ba68d17 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -498,7 +498,9 @@
allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
requirePmf = true;
break;
case SECURITY_TYPE_EAP_SUITE_B:
@@ -517,7 +519,9 @@
allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
requirePmf = true;
break;
case SECURITY_TYPE_WAPI_PSK:
@@ -631,13 +635,6 @@
public String preSharedKey;
/**
- * Optional SAE Password Id for use with WPA3-SAE. It is an ASCII string.
- * @hide
- */
- @SystemApi
- public @Nullable String saePasswordId;
-
- /**
* Four WEP keys. For each of the four values, provide either an ASCII
* string enclosed in double quotation marks (e.g., {@code "abcdef"}),
* a string of hex digits (e.g., {@code 0102030405}), or an empty string
@@ -2330,9 +2327,6 @@
sbuf.append('*');
}
- sbuf.append('\n').append(" SAE Password Id: ");
- sbuf.append(this.saePasswordId);
-
sbuf.append("\nEnterprise config:\n");
sbuf.append(enterpriseConfig);
@@ -2727,7 +2721,6 @@
providerFriendlyName = source.providerFriendlyName;
isHomeProviderNetwork = source.isHomeProviderNetwork;
preSharedKey = source.preSharedKey;
- saePasswordId = source.saePasswordId;
mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
apBand = source.apBand;
@@ -2815,7 +2808,6 @@
dest.writeLong(roamingConsortiumId);
}
dest.writeString(preSharedKey);
- dest.writeString(saePasswordId);
for (String wepKey : wepKeys) {
dest.writeString(wepKey);
}
@@ -2891,7 +2883,6 @@
config.roamingConsortiumIds[i] = in.readLong();
}
config.preSharedKey = in.readString();
- config.saePasswordId = in.readString();
for (int i = 0; i < config.wepKeys.length; i++) {
config.wepKeys[i] = in.readString();
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ff62296..5e60b26 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -727,8 +727,9 @@
/**
* If Soft Ap client is blocked, this reason code means that client doesn't exist in the
- * specified configuration {@link SoftApConfiguration.Builder#setClientList(List, List)}
- * and the {@link SoftApConfiguration.Builder#enableClientControlByUser(true)}
+ * specified configuration {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
+ * and {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
+ * and the {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
* is configured as well.
* @hide
*/
@@ -2735,27 +2736,30 @@
}
/**
- * Return the filtered ScanResults which may be authenticated by the suggested network
- * configurations.
- * @param networkSuggestions The list of {@link WifiNetworkSuggestion}
- * @param scanResults The scan results to be filtered, this is optional, if it is null or
- * empty, wifi system would use the recent scan results in the system.
- * @return The map of {@link WifiNetworkSuggestion} and the list of {@link ScanResult} which
- * may be authenticated by the corresponding network configuration.
+ * Get the filtered ScanResults which match the network configurations specified by the
+ * {@code networkSuggestionsToMatch}. Suggestions which use {@link WifiConfiguration} use
+ * SSID and the security type to match. Suggestions which use {@link PasspointConfigration}
+ * use the matching rules of Hotspot 2.0.
+ * @param networkSuggestionsToMatch The list of {@link WifiNetworkSuggestion} to match against.
+ * These may or may not be suggestions which are installed on the device.
+ * @param scanResults The scan results to be filtered. Optional - if not provided(empty list),
+ * the Wi-Fi service will use the most recent scan results which the system has.
+ * @return The map of {@link WifiNetworkSuggestion} to the list of {@link ScanResult}
+ * corresponding to networks which match them.
* @hide
*/
@SystemApi
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
@NonNull
public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
- @NonNull List<WifiNetworkSuggestion> networkSuggestions,
+ @NonNull List<WifiNetworkSuggestion> networkSuggestionsToMatch,
@Nullable List<ScanResult> scanResults) {
- if (networkSuggestions == null) {
+ if (networkSuggestionsToMatch == null) {
throw new IllegalArgumentException("networkSuggestions must not be null.");
}
try {
return mService.getMatchingScanResults(
- networkSuggestions, scanResults,
+ networkSuggestionsToMatch, scanResults,
mContext.getOpPackageName(), mContext.getFeatureId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2826,7 +2830,7 @@
*/
@Nullable
@SystemApi
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String getCountryCode() {
try {
return mService.getCountryCode();
@@ -3372,7 +3376,7 @@
*/
@NonNull
@SystemApi
- @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public SoftApConfiguration getSoftApConfiguration() {
try {
return mService.getSoftApConfiguration();
@@ -3406,9 +3410,10 @@
* If the API is called while the tethered soft AP is enabled, the configuration will apply to
* the current soft AP if the new configuration only includes
* {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
- * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(int)}
- * or {@link SoftApConfiguration.Builder#enableClientControlByUser(boolean)}
- * or {@link SoftApConfiguration.Builder#setClientList(List, List)}.
+ * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}
+ * or {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
+ * or {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
+ * or {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
*
* Otherwise, the configuration changes will be applied when the Soft AP is next started
* (the framework will not stop/start the AP).
@@ -4989,7 +4994,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void factoryReset() {
try {
mService.factoryReset(mContext.getOpPackageName());
@@ -5986,22 +5991,22 @@
}
/**
- * Callback interface for framework to receive network status changes and trigger of updating
+ * Callback interface for framework to receive network status updates and trigger of updating
* {@link WifiUsabilityStatsEntry}.
*
* @hide
*/
@SystemApi
- public interface ScoreChangeCallback {
+ public interface ScoreUpdateObserver {
/**
* Called by applications to indicate network status.
*
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
- * {@link WifiConnectedNetworkScorer#start(int)}.
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
* @param score The score representing link quality of current Wi-Fi network connection.
* Populated by connected network scorer in applications..
*/
- void onScoreChange(int sessionId, int score);
+ void notifyScoreUpdate(int sessionId, int score);
/**
* Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
@@ -6009,36 +6014,36 @@
* {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
*
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
- * {@link WifiConnectedNetworkScorer#start(int)}.
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
*/
- void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
+ void triggerUpdateOfWifiUsabilityStats(int sessionId);
}
/**
- * Callback proxy for {@link ScoreChangeCallback} objects.
+ * Callback proxy for {@link ScoreUpdateObserver} objects.
*
* @hide
*/
- private class ScoreChangeCallbackProxy implements ScoreChangeCallback {
- private final IScoreChangeCallback mScoreChangeCallback;
+ private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
+ private final IScoreUpdateObserver mScoreUpdateObserver;
- private ScoreChangeCallbackProxy(IScoreChangeCallback callback) {
- mScoreChangeCallback = callback;
+ private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
+ mScoreUpdateObserver = observer;
}
@Override
- public void onScoreChange(int sessionId, int score) {
+ public void notifyScoreUpdate(int sessionId, int score) {
try {
- mScoreChangeCallback.onScoreChange(sessionId, score);
+ mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
- public void onTriggerUpdateOfWifiUsabilityStats(int sessionId) {
+ public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
try {
- mScoreChangeCallback.onTriggerUpdateOfWifiUsabilityStats(sessionId);
+ mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6058,21 +6063,21 @@
* Called by framework to indicate the start of a network connection.
* @param sessionId The ID to indicate current Wi-Fi network connection.
*/
- void start(int sessionId);
+ void onStart(int sessionId);
/**
* Called by framework to indicate the end of a network connection.
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
- * {@link WifiConnectedNetworkScorer#start(int)}.
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
*/
- void stop(int sessionId);
+ void onStop(int sessionId);
/**
* Framework sets callback for score change events after application sets its scorer.
- * @param cbImpl The instance for {@link WifiManager#ScoreChangeCallback}. Should be
+ * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
* implemented and instantiated by framework.
*/
- void setScoreChangeCallback(@NonNull ScoreChangeCallback cbImpl);
+ void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
}
/**
@@ -6090,32 +6095,32 @@
}
@Override
- public void start(int sessionId) {
+ public void onStart(int sessionId) {
if (mVerboseLoggingEnabled) {
- Log.v(TAG, "WifiConnectedNetworkScorer: " + "start: sessionId=" + sessionId);
+ Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionId=" + sessionId);
}
Binder.clearCallingIdentity();
- mExecutor.execute(() -> mScorer.start(sessionId));
+ mExecutor.execute(() -> mScorer.onStart(sessionId));
}
@Override
- public void stop(int sessionId) {
+ public void onStop(int sessionId) {
if (mVerboseLoggingEnabled) {
- Log.v(TAG, "WifiConnectedNetworkScorer: " + "stop: sessionId=" + sessionId);
+ Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
}
Binder.clearCallingIdentity();
- mExecutor.execute(() -> mScorer.stop(sessionId));
+ mExecutor.execute(() -> mScorer.onStop(sessionId));
}
@Override
- public void setScoreChangeCallback(IScoreChangeCallback cbImpl) {
+ public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "WifiConnectedNetworkScorer: "
- + "setScoreChangeCallback: cbImpl=" + cbImpl);
+ + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
}
Binder.clearCallingIdentity();
- mExecutor.execute(() -> mScorer.setScoreChangeCallback(
- new ScoreChangeCallbackProxy(cbImpl)));
+ mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
+ new ScoreUpdateObserverProxy(observerImpl)));
}
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 9c2cad9..a310ff6 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1805,9 +1805,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
- android.Manifest.permission.CONFIGURE_WIFI_DISPLAY})
+ @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
public void setMiracastMode(@MiracastMode int mode) {
try {
mService.setMiracastMode(mode);
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
index 987fee7..34e2e3a 100644
--- a/wifi/tests/AndroidTest.xml
+++ b/wifi/tests/AndroidTest.xml
@@ -25,4 +25,10 @@
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
+
+ <!-- Only run FrameworksWifiApiTests in MTS if the Wifi Mainline module is installed. -->
+ <object type="module_controller"
+ class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.wifi" />
+ </object>
</configuration>
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 060ddf0..1a44270 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -127,8 +127,9 @@
.setMaxNumberOfClients(10)
.setAutoShutdownEnabled(true)
.setShutdownTimeoutMillis(500000)
- .enableClientControlByUser(true)
- .setClientList(testBlockedClientList, testAllowedClientList)
+ .setClientControlByUserEnabled(true)
+ .setBlockedClientList(testBlockedClientList)
+ .setAllowedClientList(testAllowedClientList)
.build();
assertThat(original.getPassphrase()).isEqualTo("secretsecret");
assertThat(original.getSecurityType()).isEqualTo(
@@ -264,7 +265,9 @@
ArrayList<MacAddress> testBlockedClientList = new ArrayList<>();
testBlockedClientList.add(testMacAddress_1);
SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
- configBuilder.setClientList(testBlockedClientList, testAllowedClientList);
+ configBuilder.setBlockedClientList(testBlockedClientList)
+ .setAllowedClientList(testAllowedClientList)
+ .build();
}
@Test
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 91c74f3..e210e4f 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -423,7 +423,9 @@
assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE));
assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
assertTrue(config.requirePmf);
}
@@ -440,7 +442,9 @@
assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE));
assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
assertTrue(config.requirePmf);
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 76ac837..90d6241 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -2349,23 +2349,24 @@
}
/**
- * Verify that Wi-Fi connected scorer receives score change callback after registeration.
+ * Verify that Wi-Fi connected scorer receives score update observer after registeration.
*/
@Test
- public void verifyScorerReceiveScoreChangeCallbackAfterRegistration() throws Exception {
+ public void verifyScorerReceiveScoreUpdateObserverAfterRegistration() throws Exception {
mExecutor = new SynchronousExecutor();
mWifiManager.setWifiConnectedNetworkScorer(mExecutor, mWifiConnectedNetworkScorer);
ArgumentCaptor<IWifiConnectedNetworkScorer.Stub> scorerCaptor =
ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
scorerCaptor.capture());
- scorerCaptor.getValue().setScoreChangeCallback(any());
+ scorerCaptor.getValue().onSetScoreUpdateObserver(any());
mLooper.dispatchAll();
- verify(mWifiConnectedNetworkScorer).setScoreChangeCallback(any());
+ verify(mWifiConnectedNetworkScorer).onSetScoreUpdateObserver(any());
}
/**
- * Verify that Wi-Fi connected scorer receives session ID when start/stop methods are called.
+ * Verify that Wi-Fi connected scorer receives session ID when onStart/onStop methods
+ * are called.
*/
@Test
public void verifyScorerReceiveSessionIdWhenStartStopIsCalled() throws Exception {
@@ -2375,11 +2376,11 @@
ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
callbackCaptor.capture());
- callbackCaptor.getValue().start(0);
- callbackCaptor.getValue().stop(10);
+ callbackCaptor.getValue().onStart(0);
+ callbackCaptor.getValue().onStop(10);
mLooper.dispatchAll();
- verify(mWifiConnectedNetworkScorer).start(0);
- verify(mWifiConnectedNetworkScorer).stop(10);
+ verify(mWifiConnectedNetworkScorer).onStart(0);
+ verify(mWifiConnectedNetworkScorer).onStop(10);
}
@Test