Merge "Exposing flickerlib classes and layer tracing to sysui"
am: e25075b2fb
Change-Id: I182eef2c7f93d68bcdceaec3fcdfaf9615eda0ea
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index b347a78..39792ce 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -638,4 +638,14 @@
* native InputManager before proceeding with tests.
*/
void syncInputTransactions();
+
+ /**
+ * Returns whether SurfaceFlinger layer tracing is enabled.
+ */
+ boolean isLayerTracing();
+
+ /**
+ * Enables/disables SurfaceFlinger layer tracing.
+ */
+ void setLayerTracing(boolean enabled);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c108752..ec970d2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -7806,4 +7806,64 @@
0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */);
}
}
+
+ /** Return whether layer tracing is enabled */
+ public boolean isLayerTracing() {
+ mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.DUMP,
+ "isLayerTracing");
+ long token = Binder.clearCallingIdentity();
+ try {
+ Parcel data = null;
+ Parcel reply = null;
+ try {
+ IBinder sf = ServiceManager.getService("SurfaceFlinger");
+ if (sf != null) {
+ reply = Parcel.obtain();
+ data = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ sf.transact(/* LAYER_TRACE_STATUS_CODE */ 1026, data, reply, 0 /* flags */);
+ return reply.readBoolean();
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to get layer tracing");
+ } finally {
+ if (data != null) {
+ data.recycle();
+ }
+ if (reply != null) {
+ reply.recycle();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ return false;
+ }
+
+ /** Enable or disable layer tracing */
+ public void setLayerTracing(boolean enabled) {
+ mAtmInternal.enforceCallerIsRecentsOrHasPermission(android.Manifest.permission.DUMP,
+ "setLayerTracing");
+ long token = Binder.clearCallingIdentity();
+ try {
+ Parcel data = null;
+ try {
+ IBinder sf = ServiceManager.getService("SurfaceFlinger");
+ if (sf != null) {
+ data = Parcel.obtain();
+ data.writeInterfaceToken("android.ui.ISurfaceComposer");
+ data.writeInt(enabled ? 1 : 0);
+ sf.transact(/* LAYER_TRACE_CONTROL_CODE */ 1025, data, null, 0 /* flags */);
+ }
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to set layer tracing");
+ } finally {
+ if (data != null) {
+ data.recycle();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
}
diff --git a/tests/FlickerTests/lib/Android.bp b/tests/FlickerTests/lib/Android.bp
index 5d8ed2c..e0f0188 100644
--- a/tests/FlickerTests/lib/Android.bp
+++ b/tests/FlickerTests/lib/Android.bp
@@ -30,10 +30,23 @@
}
java_library {
+ name: "flickerlib_without_helpers",
+ platform_apis: true,
+ srcs: ["src/**/*.java"],
+ exclude_srcs: ["src/**/helpers/*.java"],
+ static_libs: [
+ "cts-wm-util",
+ "platformprotosnano",
+ "layersprotosnano",
+ "truth-prebuilt"
+ ],
+}
+
+java_library {
name: "flickerautomationhelperlib",
sdk_version: "test_current",
srcs: [
- "src/com/android/server/wm/flicker/AutomationUtils.java",
+ "src/com/android/server/wm/flicker/helpers/AutomationUtils.java",
"src/com/android/server/wm/flicker/WindowUtils.java",
],
static_libs: [
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/Assertions.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/Assertions.java
index 84f9f871..38255ee 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/Assertions.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/Assertions.java
@@ -24,14 +24,14 @@
* results. Assertions are functions that are applied over a single trace entry and returns a
* result which includes a detailed reason if the assertion fails.
*/
-class Assertions {
+public class Assertions {
/**
* Checks assertion on a single trace entry.
*
* @param <T> trace entry type to perform the assertion on.
*/
@FunctionalInterface
- interface TraceAssertion<T> extends Function<T, Result> {
+ public interface TraceAssertion<T> extends Function<T, Result> {
/**
* Returns an assertion that represents the logical negation of this assertion.
*
@@ -46,7 +46,7 @@
* Checks assertion on a single layers trace entry.
*/
@FunctionalInterface
- interface LayersTraceAssertion extends TraceAssertion<LayersTrace.Entry> {
+ public interface LayersTraceAssertion extends TraceAssertion<LayersTrace.Entry> {
}
@@ -54,11 +54,11 @@
* Utility class to store assertions with an identifier to help generate more useful debug
* data when dealing with multiple assertions.
*/
- static class NamedAssertion<T> {
- final TraceAssertion<T> assertion;
- final String name;
+ public static class NamedAssertion<T> {
+ public final TraceAssertion<T> assertion;
+ public final String name;
- NamedAssertion(TraceAssertion<T> assertion, String name) {
+ public NamedAssertion(TraceAssertion<T> assertion, String name) {
this.assertion = assertion;
this.name = name;
}
@@ -67,21 +67,21 @@
/**
* Contains the result of an assertion including the reason for failed assertions.
*/
- static class Result {
- static final String NEGATION_PREFIX = "!";
- final boolean success;
- final long timestamp;
- final String assertionName;
- final String reason;
+ public static class Result {
+ public static final String NEGATION_PREFIX = "!";
+ public final boolean success;
+ public final long timestamp;
+ public final String assertionName;
+ public final String reason;
- Result(boolean success, long timestamp, String assertionName, String reason) {
+ public Result(boolean success, long timestamp, String assertionName, String reason) {
this.success = success;
this.timestamp = timestamp;
this.assertionName = assertionName;
this.reason = reason;
}
- Result(boolean success, String reason) {
+ public Result(boolean success, String reason) {
this.success = success;
this.reason = reason;
this.assertionName = "";
@@ -91,7 +91,7 @@
/**
* Returns the negated {@code Result} and adds a negation prefix to the assertion name.
*/
- Result negate() {
+ public Result negate() {
String negatedAssertionName;
if (this.assertionName.startsWith(NEGATION_PREFIX)) {
negatedAssertionName = this.assertionName.substring(NEGATION_PREFIX.length() + 1);
@@ -101,11 +101,11 @@
return new Result(!this.success, this.timestamp, negatedAssertionName, this.reason);
}
- boolean passed() {
+ public boolean passed() {
return this.success;
}
- boolean failed() {
+ public boolean failed() {
return !this.success;
}
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AssertionsChecker.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AssertionsChecker.java
index 3c65d3c..5c4df81 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AssertionsChecker.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AssertionsChecker.java
@@ -38,11 +38,11 @@
private AssertionOption mOption = AssertionOption.NONE;
private List<NamedAssertion<T>> mAssertions = new LinkedList<>();
- void add(Assertions.TraceAssertion<T> assertion, String name) {
+ public void add(Assertions.TraceAssertion<T> assertion, String name) {
mAssertions.add(new NamedAssertion<>(assertion, name));
}
- void filterByRange(long startTime, long endTime) {
+ public void filterByRange(long startTime, long endTime) {
mFilterEntriesByRange = true;
mFilterStartTime = startTime;
mFilterEndTime = endTime;
@@ -75,7 +75,7 @@
* @param entries list of entries to perform assertions on
* @return list of failed assertion results
*/
- List<Result> test(List<T> entries) {
+ public List<Result> test(List<T> entries) {
List<T> filteredEntries;
List<Result> failures;
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/ITraceEntry.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/ITraceEntry.java
index 9525f41..c47f7f4 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/ITraceEntry.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/ITraceEntry.java
@@ -19,7 +19,7 @@
/**
* Common interface for Layer and WindowManager trace entries.
*/
-interface ITraceEntry {
+public interface ITraceEntry {
/**
* @return timestamp of current entry
*/
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/LayersTrace.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/LayersTrace.java
index 660ec0f..68986d4 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/LayersTrace.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/LayersTrace.java
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker;
-import android.annotation.Nullable;
import android.graphics.Rect;
import android.surfaceflinger.nano.Layers.LayerProto;
import android.surfaceflinger.nano.Layers.RectProto;
@@ -25,11 +24,14 @@
import android.surfaceflinger.nano.Layerstrace.LayersTraceProto;
import android.util.SparseArray;
+import androidx.annotation.Nullable;
+
import com.android.server.wm.flicker.Assertions.Result;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -57,7 +59,7 @@
* @param data binary proto data
* @param source Path to source of data for additional debug information
*/
- static LayersTrace parseFrom(byte[] data, Path source) {
+ public static LayersTrace parseFrom(byte[] data, Path source) {
List<Entry> entries = new ArrayList<>();
LayersTraceFileProto fileProto;
try {
@@ -79,15 +81,15 @@
*
* @param data binary proto data
*/
- static LayersTrace parseFrom(byte[] data) {
+ public static LayersTrace parseFrom(byte[] data) {
return parseFrom(data, null);
}
- List<Entry> getEntries() {
+ public List<Entry> getEntries() {
return mEntries;
}
- Entry getEntry(long timestamp) {
+ public Entry getEntry(long timestamp) {
Optional<Entry> entry = mEntries.stream()
.filter(e -> e.getTimestamp() == timestamp)
.findFirst();
@@ -97,14 +99,14 @@
return entry.get();
}
- Optional<Path> getSource() {
+ public Optional<Path> getSource() {
return Optional.ofNullable(mSource);
}
/**
* Represents a single Layer trace entry.
*/
- static class Entry implements ITraceEntry {
+ public static class Entry implements ITraceEntry {
private long mTimestamp;
private List<Layer> mRootLayers; // hierarchical representation of layers
private List<Layer> mFlattenedLayers = null;
@@ -117,7 +119,7 @@
/**
* Constructs the layer hierarchy from a flattened list of layers.
*/
- static Entry fromFlattenedLayers(long timestamp, LayerProto[] protos) {
+ public static Entry fromFlattenedLayers(long timestamp, LayerProto[] protos) {
SparseArray<Layer> layerMap = new SparseArray<>();
ArrayList<Layer> orphans = new ArrayList<>();
for (LayerProto proto : protos) {
@@ -181,7 +183,7 @@
/**
* Checks if a region specified by {@code testRect} is covered by all visible layers.
*/
- Result coversRegion(Rect testRect) {
+ public Result coversRegion(Rect testRect) {
String assertionName = "coversRegion";
Collection<Layer> layers = asFlattenedLayers();
@@ -224,7 +226,7 @@
* Checks if a layer with name {@code layerName} has a visible region
* {@code expectedVisibleRegion}.
*/
- Result hasVisibleRegion(String layerName, Rect expectedVisibleRegion) {
+ public Result hasVisibleRegion(String layerName, Rect expectedVisibleRegion) {
String assertionName = "hasVisibleRegion";
String reason = "Could not find " + layerName;
for (Layer layer : asFlattenedLayers()) {
@@ -252,7 +254,7 @@
/**
* Checks if a layer with name {@code layerName} is visible.
*/
- Result isVisible(String layerName) {
+ public Result isVisible(String layerName) {
String assertionName = "isVisible";
String reason = "Could not find " + layerName;
for (Layer layer : asFlattenedLayers()) {
@@ -277,24 +279,27 @@
return mTimestamp;
}
- List<Layer> getRootLayers() {
+ public List<Layer> getRootLayers() {
return mRootLayers;
}
- List<Layer> asFlattenedLayers() {
+ /**
+ * Returns all layers as a flattened list using a depth first traversal.
+ */
+ public List<Layer> asFlattenedLayers() {
if (mFlattenedLayers == null) {
- mFlattenedLayers = new ArrayList<>();
+ mFlattenedLayers = new LinkedList<>();
ArrayList<Layer> pendingLayers = new ArrayList<>(this.mRootLayers);
while (!pendingLayers.isEmpty()) {
Layer layer = pendingLayers.remove(0);
mFlattenedLayers.add(layer);
- pendingLayers.addAll(layer.mChildren);
+ pendingLayers.addAll(0, layer.mChildren);
}
}
return mFlattenedLayers;
}
- Rect getVisibleBounds(String layerName) {
+ public Rect getVisibleBounds(String layerName) {
List<Layer> layers = asFlattenedLayers();
for (Layer layer : layers) {
if (layer.mProto.name.contains(layerName) && layer.isVisible()) {
@@ -308,12 +313,12 @@
/**
* Represents a single layer with links to its parent and child layers.
*/
- static class Layer {
+ public static class Layer {
@Nullable
- LayerProto mProto;
- List<Layer> mChildren;
+ public LayerProto mProto;
+ public List<Layer> mChildren;
@Nullable
- Layer mParent = null;
+ public Layer mParent = null;
private Layer(LayerProto proto) {
this.mProto = proto;
@@ -328,16 +333,16 @@
this.mParent = parentLayer;
}
- int getId() {
+ public int getId() {
return mProto.id;
}
- boolean isActiveBufferEmpty() {
+ public boolean isActiveBufferEmpty() {
return this.mProto.activeBuffer == null || this.mProto.activeBuffer.height == 0
|| this.mProto.activeBuffer.width == 0;
}
- boolean isVisibleRegionEmpty() {
+ public boolean isVisibleRegionEmpty() {
if (this.mProto.visibleRegion == null) {
return true;
}
@@ -345,32 +350,35 @@
return visibleRect.height() == 0 || visibleRect.width() == 0;
}
- boolean isHidden() {
+ public boolean isHidden() {
return (this.mProto.flags & /* FLAG_HIDDEN */ 0x1) != 0x0;
}
- boolean isVisible() {
- return (!isActiveBufferEmpty() || isColorLayer()) &&
- !isHidden() && this.mProto.color.a > 0 && !isVisibleRegionEmpty();
+ public boolean isVisible() {
+ return (!isActiveBufferEmpty() || isColorLayer())
+ && !isHidden()
+ && this.mProto.color != null
+ && this.mProto.color.a > 0
+ && !isVisibleRegionEmpty();
}
- boolean isColorLayer() {
+ public boolean isColorLayer() {
return this.mProto.type.equals("ColorLayer");
}
- boolean isRootLayer() {
+ public boolean isRootLayer() {
return mParent == null || mParent.mProto == null;
}
- boolean isInvisible() {
+ public boolean isInvisible() {
return !isVisible();
}
- boolean isHiddenByParent() {
+ public boolean isHiddenByParent() {
return !isRootLayer() && (mParent.isHidden() || mParent.isHiddenByParent());
}
- String getHiddenByParentReason() {
+ public String getHiddenByParentReason() {
String reason = "Layer " + mProto.name;
if (isHiddenByParent()) {
reason += " is hidden by parent: " + mParent.mProto.name;
@@ -380,7 +388,7 @@
return reason;
}
- String getVisibilityReason() {
+ public String getVisibilityReason() {
String reason = "Layer " + mProto.name;
if (isVisible()) {
reason += " is visible:";
@@ -399,7 +407,7 @@
if (isHidden()) {
reason += " flags=" + this.mProto.flags + " (FLAG_HIDDEN set)";
}
- if (this.mProto.color.a == 0) {
+ if (this.mProto.color == null || this.mProto.color.a == 0) {
reason += " color.a=0";
}
if (isVisibleRegionEmpty()) {
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/LayersTraceSubject.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/LayersTraceSubject.java
index 4085810..4a5129e 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/LayersTraceSubject.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/LayersTraceSubject.java
@@ -19,9 +19,10 @@
import static com.google.common.truth.Truth.assertAbout;
import static com.google.common.truth.Truth.assertWithMessage;
-import android.annotation.Nullable;
import android.graphics.Rect;
+import androidx.annotation.Nullable;
+
import com.android.server.wm.flicker.Assertions.Result;
import com.android.server.wm.flicker.LayersTrace.Entry;
import com.android.server.wm.flicker.TransitionRunner.TransitionResult;
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/TransitionRunner.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/TransitionRunner.java
index 0a3fe3c..241a1c0 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/TransitionRunner.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/TransitionRunner.java
@@ -16,10 +16,12 @@
package com.android.server.wm.flicker;
-import android.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
+import static com.android.server.wm.flicker.monitor.ITransitionMonitor.OUTPUT_DIR;
+
import android.util.Log;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.test.InstrumentationRegistry;
import com.android.server.wm.flicker.monitor.ITransitionMonitor;
@@ -89,7 +91,7 @@
* }
* </pre>
*/
-class TransitionRunner {
+public class TransitionRunner {
private static final String TAG = "FLICKER";
private final ScreenRecorder mScreenRecorder;
private final WindowManagerTraceMonitor mWmTraceMonitor;
@@ -128,8 +130,12 @@
mTestTag = builder.mTestTag;
}
- static TransitionBuilder newBuilder() {
- return new TransitionBuilder();
+ public static TransitionBuilder newBuilder() {
+ return newBuilder(OUTPUT_DIR.toString());
+ }
+
+ public static TransitionBuilder newBuilder(String outputDir) {
+ return new TransitionBuilder(outputDir);
}
/**
@@ -138,7 +144,7 @@
*
* @return itself
*/
- TransitionRunner run() {
+ public TransitionRunner run() {
mResults = new ArrayList<>();
mAllRunsMonitors.forEach(ITransitionMonitor::start);
mBeforeAlls.forEach(Runnable::run);
@@ -159,8 +165,7 @@
mAfterAlls.forEach(Runnable::run);
mAllRunsMonitors.forEach(monitor -> {
monitor.stop();
- Path path = monitor.save(mTestTag);
- Log.e(TAG, "Video saved to " + path.toString());
+ monitor.save(mTestTag);
});
return this;
}
@@ -170,7 +175,7 @@
*
* @return list of transition results.
*/
- List<TransitionResult> getResults() {
+ public List<TransitionResult> getResults() {
if (mResults == null) {
throw new IllegalStateException("Results do not exist!");
}
@@ -182,7 +187,7 @@
*
* @return list of transition results.
*/
- void deleteResults() {
+ public void deleteResults() {
if (mResults == null) {
return;
}
@@ -228,33 +233,33 @@
@VisibleForTesting
public static class TransitionResult {
@Nullable
- final Path layersTrace;
+ public final Path layersTrace;
@Nullable
- final Path windowManagerTrace;
+ public final Path windowManagerTrace;
@Nullable
- final Path screenCaptureVideo;
+ public final Path screenCaptureVideo;
private boolean flaggedForSaving;
- TransitionResult(@Nullable Path layersTrace, @Nullable Path windowManagerTrace,
+ public TransitionResult(@Nullable Path layersTrace, @Nullable Path windowManagerTrace,
@Nullable Path screenCaptureVideo) {
this.layersTrace = layersTrace;
this.windowManagerTrace = windowManagerTrace;
this.screenCaptureVideo = screenCaptureVideo;
}
- void flagForSaving() {
+ public void flagForSaving() {
flaggedForSaving = true;
}
- boolean canDelete() {
+ public boolean canDelete() {
return !flaggedForSaving;
}
- boolean layersTraceExists() {
+ public boolean layersTraceExists() {
return layersTrace != null && layersTrace.toFile().exists();
}
- byte[] getLayersTrace() {
+ public byte[] getLayersTrace() {
try {
return Files.toByteArray(this.layersTrace.toFile());
} catch (IOException e) {
@@ -262,11 +267,11 @@
}
}
- Path getLayersTracePath() {
+ public Path getLayersTracePath() {
return layersTrace;
}
- boolean windowManagerTraceExists() {
+ public boolean windowManagerTraceExists() {
return windowManagerTrace != null && windowManagerTrace.toFile().exists();
}
@@ -278,19 +283,19 @@
}
}
- Path getWindowManagerTracePath() {
+ public Path getWindowManagerTracePath() {
return windowManagerTrace;
}
- boolean screenCaptureVideoExists() {
+ public boolean screenCaptureVideoExists() {
return screenCaptureVideo != null && screenCaptureVideo.toFile().exists();
}
- Path screenCaptureVideoPath() {
+ public Path screenCaptureVideoPath() {
return screenCaptureVideo;
}
- void delete() {
+ public void delete() {
if (layersTraceExists()) layersTrace.toFile().delete();
if (windowManagerTraceExists()) windowManagerTrace.toFile().delete();
if (screenCaptureVideoExists()) screenCaptureVideo.toFile().delete();
@@ -300,7 +305,7 @@
/**
* Builds a {@link TransitionRunner} instance.
*/
- static class TransitionBuilder {
+ public static class TransitionBuilder {
private ScreenRecorder mScreenRecorder;
private WindowManagerTraceMonitor mWmTraceMonitor;
private LayersTraceMonitor mLayersTraceMonitor;
@@ -323,15 +328,15 @@
private boolean mRecordAllRuns = false;
- TransitionBuilder() {
+ public TransitionBuilder(String outputDir) {
mScreenRecorder = new ScreenRecorder();
- mWmTraceMonitor = new WindowManagerTraceMonitor();
- mLayersTraceMonitor = new LayersTraceMonitor();
+ mWmTraceMonitor = new WindowManagerTraceMonitor(outputDir);
+ mLayersTraceMonitor = new LayersTraceMonitor(outputDir);
mFrameStatsMonitor = new
WindowAnimationFrameStatsMonitor(InstrumentationRegistry.getInstrumentation());
}
- TransitionRunner build() {
+ public TransitionRunner build() {
if (mCaptureWindowManagerTrace) {
mPerRunMonitors.add(mWmTraceMonitor);
}
@@ -355,52 +360,52 @@
return new TransitionRunner(this);
}
- TransitionBuilder runBeforeAll(Runnable runnable) {
+ public TransitionBuilder runBeforeAll(Runnable runnable) {
mBeforeAlls.add(runnable);
return this;
}
- TransitionBuilder runBefore(Runnable runnable) {
+ public TransitionBuilder runBefore(Runnable runnable) {
mBefores.add(runnable);
return this;
}
- TransitionBuilder run(Runnable runnable) {
+ public TransitionBuilder run(Runnable runnable) {
mTransitions.add(runnable);
return this;
}
- TransitionBuilder runAfter(Runnable runnable) {
+ public TransitionBuilder runAfter(Runnable runnable) {
mAfters.add(runnable);
return this;
}
- TransitionBuilder runAfterAll(Runnable runnable) {
+ public TransitionBuilder runAfterAll(Runnable runnable) {
mAfterAlls.add(runnable);
return this;
}
- TransitionBuilder repeat(int iterations) {
+ public TransitionBuilder repeat(int iterations) {
mIterations = iterations;
return this;
}
- TransitionBuilder skipWindowManagerTrace() {
+ public TransitionBuilder skipWindowManagerTrace() {
mCaptureWindowManagerTrace = false;
return this;
}
- TransitionBuilder skipLayersTrace() {
+ public TransitionBuilder skipLayersTrace() {
mCaptureLayersTrace = false;
return this;
}
- TransitionBuilder includeJankyRuns() {
+ public TransitionBuilder includeJankyRuns() {
mRunJankFree = false;
return this;
}
- TransitionBuilder recordEachRun() {
+ public TransitionBuilder recordEachRun() {
if (mRecordAllRuns) {
throw new IllegalArgumentException("Invalid option with recordAllRuns");
}
@@ -408,7 +413,7 @@
return this;
}
- TransitionBuilder recordAllRuns() {
+ public TransitionBuilder recordAllRuns() {
if (mRecordEachRun) {
throw new IllegalArgumentException("Invalid option with recordEachRun");
}
@@ -416,7 +421,11 @@
return this;
}
- TransitionBuilder withTag(String testTag) {
+ public TransitionBuilder withTag(String testTag) {
+ if (testTag.contains(" ")) {
+ throw new IllegalArgumentException("The test tag can not contain spaces since it "
+ + "is a part of the file name");
+ }
mTestTag = testTag;
return this;
}
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowManagerTrace.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowManagerTrace.java
index e3592eb..412e72d8 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowManagerTrace.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowManagerTrace.java
@@ -16,7 +16,7 @@
package com.android.server.wm.flicker;
-import android.annotation.Nullable;
+import androidx.annotation.Nullable;
import com.android.server.wm.flicker.Assertions.Result;
import com.android.server.wm.nano.AppWindowTokenProto;
@@ -58,7 +58,7 @@
* @param data binary proto data
* @param source Path to source of data for additional debug information
*/
- static WindowManagerTrace parseFrom(byte[] data, Path source) {
+ public static WindowManagerTrace parseFrom(byte[] data, Path source) {
List<Entry> entries = new ArrayList<>();
WindowManagerTraceFileProto fileProto;
@@ -73,7 +73,7 @@
return new WindowManagerTrace(entries, source);
}
- static WindowManagerTrace parseFrom(byte[] data) {
+ public static WindowManagerTrace parseFrom(byte[] data) {
return parseFrom(data, null);
}
@@ -81,7 +81,7 @@
return mEntries;
}
- Entry getEntry(long timestamp) {
+ public Entry getEntry(long timestamp) {
Optional<Entry> entry = mEntries.stream()
.filter(e -> e.getTimestamp() == timestamp)
.findFirst();
@@ -91,17 +91,17 @@
return entry.get();
}
- Optional<Path> getSource() {
+ public Optional<Path> getSource() {
return Optional.ofNullable(mSource);
}
/**
* Represents a single WindowManager trace entry.
*/
- static class Entry implements ITraceEntry {
+ public static class Entry implements ITraceEntry {
private final WindowManagerTraceProto mProto;
- Entry(WindowManagerTraceProto proto) {
+ public Entry(WindowManagerTraceProto proto) {
mProto = proto;
}
@@ -162,7 +162,7 @@
/**
* Checks if aboveAppWindow with {@code windowTitle} is visible.
*/
- Result isAboveAppWindowVisible(String windowTitle) {
+ public Result isAboveAppWindowVisible(String windowTitle) {
WindowTokenProto[] windowTokenProtos = mProto.windowManagerService
.rootWindowContainer
.displays[DEFAULT_DISPLAY].aboveAppWindows;
@@ -173,7 +173,7 @@
/**
* Checks if belowAppWindow with {@code windowTitle} is visible.
*/
- Result isBelowAppWindowVisible(String windowTitle) {
+ public Result isBelowAppWindowVisible(String windowTitle) {
WindowTokenProto[] windowTokenProtos = mProto.windowManagerService
.rootWindowContainer
.displays[DEFAULT_DISPLAY].belowAppWindows;
@@ -185,7 +185,7 @@
/**
* Checks if imeWindow with {@code windowTitle} is visible.
*/
- Result isImeWindowVisible(String windowTitle) {
+ public Result isImeWindowVisible(String windowTitle) {
WindowTokenProto[] windowTokenProtos = mProto.windowManagerService
.rootWindowContainer
.displays[DEFAULT_DISPLAY].imeWindows;
@@ -197,7 +197,7 @@
/**
* Checks if app window with {@code windowTitle} is on top.
*/
- Result isVisibleAppWindowOnTop(String windowTitle) {
+ public Result isVisibleAppWindowOnTop(String windowTitle) {
String topAppWindow = getTopVisibleAppWindow();
boolean success = topAppWindow.contains(windowTitle);
String reason = "wanted=" + windowTitle + " found=" + topAppWindow;
@@ -207,7 +207,7 @@
/**
* Checks if app window with {@code windowTitle} is visible.
*/
- Result isAppWindowVisible(String windowTitle) {
+ public Result isAppWindowVisible(String windowTitle) {
final String assertionName = "isAppWindowVisible";
boolean titleFound = false;
StackProto[] stacks = mProto.windowManagerService.rootWindowContainer
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowUtils.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowUtils.java
index c54396f..3d25fbe 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowUtils.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WindowUtils.java
@@ -28,9 +28,9 @@
/**
* Helper functions to retrieve system window sizes and positions.
*/
-class WindowUtils {
+public class WindowUtils {
- static Rect getDisplayBounds() {
+ public static Rect getDisplayBounds() {
Point display = new Point();
WindowManager wm =
(WindowManager) InstrumentationRegistry.getContext().getSystemService(
@@ -46,7 +46,7 @@
return wm.getDefaultDisplay().getRotation();
}
- static Rect getDisplayBounds(int requestedRotation) {
+ public static Rect getDisplayBounds(int requestedRotation) {
Rect displayBounds = getDisplayBounds();
int currentDisplayRotation = getCurrentRotation();
@@ -66,7 +66,7 @@
}
- static Rect getAppPosition(int requestedRotation) {
+ public static Rect getAppPosition(int requestedRotation) {
Rect displayBounds = getDisplayBounds();
int currentDisplayRotation = getCurrentRotation();
@@ -85,7 +85,7 @@
return new Rect(0, 0, displayBounds.width(), displayBounds.height());
}
- static Rect getStatusBarPosition(int requestedRotation) {
+ public static Rect getStatusBarPosition(int requestedRotation) {
Resources resources = InstrumentationRegistry.getContext().getResources();
String resourceName;
Rect displayBounds = getDisplayBounds();
@@ -104,7 +104,7 @@
return new Rect(0, 0, width, height);
}
- static Rect getNavigationBarPosition(int requestedRotation) {
+ public static Rect getNavigationBarPosition(int requestedRotation) {
Resources resources = InstrumentationRegistry.getContext().getResources();
Rect displayBounds = getDisplayBounds();
int displayWidth = Math.min(displayBounds.width(), displayBounds.height());
@@ -129,13 +129,13 @@
}
}
- static int getNavigationBarHeight() {
+ public static int getNavigationBarHeight() {
Resources resources = InstrumentationRegistry.getContext().getResources();
int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
return resources.getDimensionPixelSize(resourceId);
}
- static int getDockedStackDividerInset() {
+ public static int getDockedStackDividerInset() {
Resources resources = InstrumentationRegistry.getContext().getResources();
int resourceId = resources.getIdentifier("docked_stack_divider_insets", "dimen",
"android");
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WmTraceSubject.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WmTraceSubject.java
index e76da6e..064cc27 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WmTraceSubject.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/WmTraceSubject.java
@@ -19,7 +19,7 @@
import static com.google.common.truth.Truth.assertAbout;
import static com.google.common.truth.Truth.assertWithMessage;
-import android.annotation.Nullable;
+import androidx.annotation.Nullable;
import com.android.server.wm.flicker.Assertions.Result;
import com.android.server.wm.flicker.TransitionRunner.TransitionResult;
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AutomationUtils.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/helpers/AutomationUtils.java
similarity index 95%
rename from tests/FlickerTests/lib/src/com/android/server/wm/flicker/AutomationUtils.java
rename to tests/FlickerTests/lib/src/com/android/server/wm/flicker/helpers/AutomationUtils.java
index e00a247..6821ff0 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/AutomationUtils.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/helpers/AutomationUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.wm.flicker;
+package com.android.server.wm.flicker.helpers;
import static android.os.SystemClock.sleep;
import static android.system.helpers.OverviewHelper.isRecentsInLauncher;
@@ -44,6 +44,8 @@
import androidx.test.InstrumentationRegistry;
+import com.android.server.wm.flicker.WindowUtils;
+
/**
* Collection of UI Automation helper functions.
*/
@@ -70,14 +72,14 @@
* This removes some delays when using the UIAutomator library required to create fast UI
* transitions.
*/
- static void setFastWait() {
+ public static void setFastWait() {
Configurator.getInstance().setWaitForIdleTimeout(0);
}
/**
* Reverts {@link android.app.UiAutomation#waitForIdle(long, long)} to default behavior.
*/
- static void setDefaultWait() {
+ public static void setDefaultWait() {
Configurator.getInstance().setWaitForIdleTimeout(10000);
}
@@ -124,7 +126,7 @@
device.waitForIdle();
}
- static void clearRecents(UiDevice device) {
+ public static void clearRecents(UiDevice device) {
if (isQuickstepEnabled(device)) {
openQuickstep(device);
@@ -201,7 +203,7 @@
sleep(2000);
}
- static void resizeSplitScreen(UiDevice device, Rational windowHeightRatio) {
+ public static void resizeSplitScreen(UiDevice device, Rational windowHeightRatio) {
BySelector dividerSelector = By.res(SYSTEMUI_PACKAGE, "docked_divider_handle");
UiObject2 divider = device.wait(Until.findObject(dividerSelector), FIND_TIMEOUT);
assertNotNull("Unable to find Split screen divider", divider);
@@ -218,7 +220,7 @@
sleep(2000);
}
- static void closePipWindow(UiDevice device) {
+ public static void closePipWindow(UiDevice device) {
UiObject2 pipWindow = device.findObject(
By.res(SYSTEMUI_PACKAGE, "background"));
pipWindow.click();
@@ -229,7 +231,7 @@
sleep(2000);
}
- static void expandPipWindow(UiDevice device) {
+ public static void expandPipWindow(UiDevice device) {
UiObject2 pipWindow = device.findObject(
By.res(SYSTEMUI_PACKAGE, "background"));
pipWindow.click();
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/LayersTraceMonitor.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/LayersTraceMonitor.java
index c55d068..da75b3e 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/LayersTraceMonitor.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/LayersTraceMonitor.java
@@ -16,21 +16,22 @@
package com.android.server.wm.flicker.monitor;
-import android.os.IBinder;
-import android.os.Parcel;
import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.Log;
+import android.view.IWindowManager;
+import android.view.WindowManagerGlobal;
/**
* Captures Layers trace from SurfaceFlinger.
*/
public class LayersTraceMonitor extends TraceMonitor {
- private static final String TAG = "LayersTraceMonitor";
- private IBinder mSurfaceFlinger = ServiceManager.getService("SurfaceFlinger");
+ private IWindowManager mWm = WindowManagerGlobal.getWindowManagerService();
public LayersTraceMonitor() {
- traceFileName = "layers_trace.pb";
+ this(OUTPUT_DIR.toString());
+ }
+
+ public LayersTraceMonitor(String outputDir) {
+ super(outputDir, "layers_trace.pb");
}
@Override
@@ -45,30 +46,19 @@
@Override
public boolean isEnabled() throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- mSurfaceFlinger.transact(/* LAYER_TRACE_STATUS_CODE */ 1026,
- data, reply, 0 /* flags */);
- return reply.readBoolean();
+ try {
+ return mWm.isLayerTracing();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ return false;
}
private void setEnabled(boolean isEnabled) {
- Parcel data = null;
try {
- if (mSurfaceFlinger != null) {
- data = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- data.writeInt(isEnabled ? 1 : 0);
- mSurfaceFlinger.transact( /* LAYER_TRACE_CONTROL_CODE */ 1025,
- data, null, 0 /* flags */);
- }
+ mWm.setLayerTracing(isEnabled);
} catch (RemoteException e) {
- Log.e(TAG, "Could not set layer tracing." + e.toString());
- } finally {
- if (data != null) {
- data.recycle();
- }
+ e.printStackTrace();
}
}
}
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/ScreenRecorder.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/ScreenRecorder.java
index 4787586..dce1c27 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/ScreenRecorder.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/ScreenRecorder.java
@@ -20,25 +20,25 @@
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
-import android.support.annotation.VisibleForTesting;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.nio.file.Paths;
/**
* Captures screen contents and saves it as a mp4 video file.
*/
public class ScreenRecorder implements ITransitionMonitor {
@VisibleForTesting
- static final Path DEFAULT_OUTPUT_PATH = OUTPUT_DIR.resolve("transition.mp4");
+ public static final Path DEFAULT_OUTPUT_PATH = OUTPUT_DIR.resolve("transition.mp4");
private static final String TAG = "FLICKER";
private Thread recorderThread;
@VisibleForTesting
- static Path getPath(String testTag) {
+ public static Path getPath(String testTag) {
return OUTPUT_DIR.resolve(testTag + ".mp4");
}
@@ -69,8 +69,10 @@
@Override
public Path save(String testTag) {
try {
- return Files.move(DEFAULT_OUTPUT_PATH, getPath(testTag),
+ Path targetPath = Files.move(DEFAULT_OUTPUT_PATH, getPath(testTag),
REPLACE_EXISTING);
+ Log.i(TAG, "Video saved to " + targetPath.toString());
+ return targetPath;
} catch (IOException e) {
throw new RuntimeException(e);
}
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/TraceMonitor.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/TraceMonitor.java
index 0e154ec..1ba36bb 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/TraceMonitor.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/TraceMonitor.java
@@ -20,7 +20,7 @@
import android.os.RemoteException;
-import com.android.internal.annotations.VisibleForTesting;
+import androidx.annotation.VisibleForTesting;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -34,9 +34,15 @@
public static final String TAG = "FLICKER";
private static final String TRACE_DIR = "/data/misc/wmtrace/";
- String traceFileName;
+ private Path mOutputDir;
+ public String mTraceFileName;
- abstract boolean isEnabled() throws RemoteException;
+ public abstract boolean isEnabled() throws RemoteException;
+
+ public TraceMonitor(String outputDir, String traceFileName) {
+ mOutputDir = Paths.get(outputDir);
+ mTraceFileName = traceFileName;
+ }
/**
* Saves trace file to the external storage directory suffixing the name with the testtag
@@ -53,14 +59,16 @@
public Path save(String testTag) {
OUTPUT_DIR.toFile().mkdirs();
Path traceFileCopy = getOutputTraceFilePath(testTag);
+
+ // Read the input stream fully.
String copyCommand = String.format(Locale.getDefault(), "mv %s%s %s", TRACE_DIR,
- traceFileName, traceFileCopy.toString());
+ mTraceFileName, traceFileCopy.toString());
runShellCommand(copyCommand);
return traceFileCopy;
}
@VisibleForTesting
- Path getOutputTraceFilePath(String testTag) {
- return OUTPUT_DIR.resolve(traceFileName + "_" + testTag);
+ public Path getOutputTraceFilePath(String testTag) {
+ return mOutputDir.resolve(mTraceFileName + "_" + testTag);
}
}
diff --git a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/WindowManagerTraceMonitor.java b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/WindowManagerTraceMonitor.java
index ae160b68..11de4aa 100644
--- a/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/WindowManagerTraceMonitor.java
+++ b/tests/FlickerTests/lib/src/com/android/server/wm/flicker/monitor/WindowManagerTraceMonitor.java
@@ -24,16 +24,20 @@
* Captures WindowManager trace from WindowManager.
*/
public class WindowManagerTraceMonitor extends TraceMonitor {
- private IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+ private IWindowManager mWm = WindowManagerGlobal.getWindowManagerService();
public WindowManagerTraceMonitor() {
- traceFileName = "wm_trace.pb";
+ this(OUTPUT_DIR.toString());
+ }
+
+ public WindowManagerTraceMonitor(String outputDir) {
+ super(outputDir, "wm_trace.pb");
}
@Override
public void start() {
try {
- wm.startWindowTrace();
+ mWm.startWindowTrace();
} catch (RemoteException e) {
throw new RuntimeException("Could not start trace", e);
}
@@ -42,7 +46,7 @@
@Override
public void stop() {
try {
- wm.stopWindowTrace();
+ mWm.stopWindowTrace();
} catch (RemoteException e) {
throw new RuntimeException("Could not stop trace", e);
}
@@ -50,6 +54,6 @@
@Override
public boolean isEnabled() throws RemoteException{
- return wm.isWindowTraceEnabled();
+ return mWm.isWindowTraceEnabled();
}
}
diff --git a/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitorTest.java b/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitorTest.java
index dd6fed0..f312384 100644
--- a/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitorTest.java
+++ b/tests/FlickerTests/lib/test/src/com/android/server/wm/flicker/monitor/WindowAnimationFrameStatsMonitorTest.java
@@ -16,7 +16,7 @@
package com.android.server.wm.flicker.monitor;
-import static com.android.server.wm.flicker.AutomationUtils.wakeUpAndGoToHomeScreen;
+import static com.android.server.wm.flicker.helpers.AutomationUtils.wakeUpAndGoToHomeScreen;
import androidx.test.InstrumentationRegistry;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
index 65888ac..5cf2c1c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonTransitions.java
@@ -19,12 +19,12 @@
import static android.os.SystemClock.sleep;
import static android.view.Surface.rotationToString;
-import static com.android.server.wm.flicker.AutomationUtils.clearRecents;
-import static com.android.server.wm.flicker.AutomationUtils.closePipWindow;
-import static com.android.server.wm.flicker.AutomationUtils.exitSplitScreen;
-import static com.android.server.wm.flicker.AutomationUtils.expandPipWindow;
-import static com.android.server.wm.flicker.AutomationUtils.launchSplitScreen;
-import static com.android.server.wm.flicker.AutomationUtils.stopPackage;
+import static com.android.server.wm.flicker.helpers.AutomationUtils.clearRecents;
+import static com.android.server.wm.flicker.helpers.AutomationUtils.closePipWindow;
+import static com.android.server.wm.flicker.helpers.AutomationUtils.exitSplitScreen;
+import static com.android.server.wm.flicker.helpers.AutomationUtils.expandPipWindow;
+import static com.android.server.wm.flicker.helpers.AutomationUtils.launchSplitScreen;
+import static com.android.server.wm.flicker.helpers.AutomationUtils.stopPackage;
import android.content.Context;
import android.content.Intent;
@@ -40,6 +40,7 @@
import androidx.test.InstrumentationRegistry;
import com.android.server.wm.flicker.TransitionRunner.TransitionBuilder;
+import com.android.server.wm.flicker.helpers.AutomationUtils;
/**
* Collection of common transitions which can be used to test different apps or scenarios.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
index 00e11c0..8c9d6b4d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/FlickerTestBase.java
@@ -16,7 +16,7 @@
package com.android.server.wm.flicker;
-import static com.android.server.wm.flicker.AutomationUtils.setDefaultWait;
+import static com.android.server.wm.flicker.helpers.AutomationUtils.setDefaultWait;
import static com.google.common.truth.Truth.assertWithMessage;