blob: 8ca384ed93713eade743a221dd611831da395bc3 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.contentcaptureservice.cts;
import static android.contentcaptureservice.cts.Helper.MY_EPOCH;
import static android.contentcaptureservice.cts.Helper.TAG;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_CONTEXT_UPDATED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_PAUSED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_RESUMED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_INSETS_CHANGED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING;
import static android.view.contentcapture.ContentCaptureEvent.TYPE_WINDOW_BOUNDS_CHANGED;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.app.assist.ActivityId;
import android.content.ComponentName;
import android.content.LocusId;
import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.autofill.AutofillId;
import android.view.contentcapture.ContentCaptureEvent;
import android.view.contentcapture.ContentCaptureSession;
import android.view.contentcapture.ContentCaptureSessionId;
import android.view.contentcapture.ViewNode;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.compatibility.common.util.RetryableException;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* Helper for common assertions.
*/
final class Assertions {
/**
* Asserts a session belongs to the right activity.
*/
public static void assertRightActivity(@NonNull Session session,
@NonNull ContentCaptureSessionId expectedSessionId,
@NonNull AbstractContentCaptureActivity activity) {
assertRightActivity(session, expectedSessionId, activity.getComponentName());
}
/**
* Asserts a session belongs to the right activity.
*/
public static void assertRightActivity(@NonNull Session session,
@NonNull ContentCaptureSessionId expectedSessionId,
@NonNull ComponentName componentName) {
assertWithMessage("wrong activity for %s", session)
.that(session.context.getActivityComponent()).isEqualTo(componentName);
// TODO(b/123540602): merge both or replace check above by:
// assertMainSessionContext(session, activity);
assertThat(session.id).isEqualTo(expectedSessionId);
}
/**
* Asserts the context of a main session.
*/
public static void assertMainSessionContext(@NonNull Session session,
@NonNull AbstractContentCaptureActivity activity) {
assertMainSessionContext(session, activity, /* expectedFlags= */ 0);
}
/**
* Asserts the context of a main session.
*/
public static void assertMainSessionContext(@NonNull Session session,
@NonNull AbstractContentCaptureActivity activity, int expectedFlags) {
assertWithMessage("no context on %s", session).that(session.context).isNotNull();
assertWithMessage("wrong activity for %s", session)
.that(session.context.getActivityComponent())
.isEqualTo(activity.getComponentName());
assertWithMessage("context for session %s should have displayId", session)
.that(session.context.getDisplayId()).isNotEqualTo(Display.INVALID_DISPLAY);
assertWithMessage("wrong task id for session %s", session)
.that(session.context.getTaskId()).isEqualTo(activity.getRealTaskId());
assertWithMessage("wrong flags on context for session %s", session)
.that(session.context.getFlags()).isEqualTo(expectedFlags);
assertWithMessage("context for session %s should not have ID", session)
.that(session.context.getLocusId()).isNull();
assertWithMessage("context for session %s should not have extras", session)
.that(session.context.getExtras()).isNull();
final ActivityId activityId = session.context.getActivityId();
assertWithMessage("context for session %s should have ActivityIds", session)
.that(activityId).isNotNull();
assertWithMessage("wrong task id for session %s", session)
.that(activityId.getTaskId()).isEqualTo(activity.getRealTaskId());
assertWithMessage("context for session %s should have ActivityId", session)
.that(activityId.getToken()).isNotNull();
assertWithMessage("context for session %s should have windowToken", session)
.that(session.context.getWindowToken()).isNotNull();
}
/**
* Asserts the invariants of a child session.
*/
public static void assertChildSessionContext(@NonNull Session session) {
assertWithMessage("no context on %s", session).that(session.context).isNotNull();
assertWithMessage("context for session %s should not have component", session)
.that(session.context.getActivityComponent()).isNull();
assertWithMessage("context for session %s should not have displayId", session)
.that(session.context.getDisplayId()).isEqualTo(Display.INVALID_DISPLAY);
assertWithMessage("context for session %s should not have taskId", session)
.that(session.context.getTaskId()).isEqualTo(0);
assertWithMessage("context for session %s should not have flags", session)
.that(session.context.getFlags()).isEqualTo(0);
final ActivityId activityId = session.context.getActivityId();
assertWithMessage("context for session %s should not have ActivityIds", session)
.that(activityId).isNull();
assertWithMessage("context for session %s should not have windowToken", session)
.that(session.context.getWindowToken()).isNull();
}
/**
* Asserts the invariants of a child session.
*/
public static void assertChildSessionContext(@NonNull Session session,
@NonNull String expectedId) {
assertChildSessionContext(session);
assertThat(session.context.getLocusId()).isEqualTo(new LocusId(expectedId));
}
/**
* Asserts a session belongs to the right parent
*/
public static void assertRightRelationship(@NonNull Session parent, @NonNull Session child) {
final ContentCaptureSessionId expectedParentId = parent.id;
assertWithMessage("No id on parent session %s", parent).that(expectedParentId).isNotNull();
assertWithMessage("No context on child session %s", child).that(child.context).isNotNull();
final ContentCaptureSessionId actualParentId = child.context.getParentSessionId();
assertWithMessage("No parent id on context %s of child session %s", child.context, child)
.that(actualParentId).isNotNull();
assertWithMessage("id of parent session doesn't match child").that(actualParentId)
.isEqualTo(expectedParentId);
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event, without checking for parent id.
*/
public static ViewNode assertViewWithUnknownParentAppeared(
@NonNull List<ContentCaptureEvent> events, int index, @NonNull View expectedView) {
return assertViewWithUnknownParentAppeared(events, index, expectedView,
/* expectedText= */ null);
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event for a decor view.
*
* <P>The decor view is typically internal, so there isn't much we can assert, other than its
* autofill id.
*/
public static void assertDecorViewAppeared(@NonNull List<ContentCaptureEvent> events,
int index, @NonNull View expectedDecorView) {
final ContentCaptureEvent event = assertViewAppeared(events, index);
assertWithMessage("wrong autofill id on %s (%s)", event, index)
.that(event.getViewNode().getAutofillId())
.isEqualTo(expectedDecorView.getAutofillId());
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event, without checking for parent id.
*/
public static ViewNode assertViewWithUnknownParentAppeared(
@NonNull List<ContentCaptureEvent> events, int index, @NonNull View expectedView,
@Nullable String expectedText) {
final ContentCaptureEvent event = assertViewAppeared(events, index);
final ViewNode node = event.getViewNode();
assertWithMessage("wrong class on %s (%s)", event, index).that(node.getClassName())
.isEqualTo(expectedView.getClass().getName());
assertWithMessage("wrong autofill id on %s (%s)", event, index).that(node.getAutofillId())
.isEqualTo(expectedView.getAutofillId());
if (expectedText != null) {
assertWithMessage("wrong text on %s (%s)", event, index).that(node.getText().toString())
.isEqualTo(expectedText);
}
// TODO(b/123540602): test more fields, like resource id
return node;
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event, without checking for parent id.
*/
public static ContentCaptureEvent assertViewAppeared(@NonNull List<ContentCaptureEvent> events,
int index) {
final ContentCaptureEvent event = getEvent(events, index, TYPE_VIEW_APPEARED);
final ViewNode node = event.getViewNode();
assertThat(node).isNotNull();
return event;
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event.
*/
public static void assertViewAppeared(@NonNull List<ContentCaptureEvent> events, int index,
@NonNull View expectedView, @Nullable AutofillId expectedParentId,
@Nullable String expectedText) {
final ViewNode node = assertViewWithUnknownParentAppeared(events, index, expectedView,
expectedText);
assertWithMessage("wrong parent autofill id on %s (%s)", events.get(index), index)
.that(node.getParentAutofillId()).isEqualTo(expectedParentId);
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event.
*/
public static void assertViewAppeared(@NonNull List<ContentCaptureEvent> events, int index,
@NonNull View expectedView, @Nullable AutofillId expectedParentId) {
assertViewAppeared(events, index, expectedView, expectedParentId, /* expectedText= */ null);
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event.
*/
public static void assertViewAppeared(@NonNull List<ContentCaptureEvent> events, int index,
@NonNull ContentCaptureSessionId expectedSessionId,
@NonNull View expectedView, @Nullable AutofillId expectedParentId) {
assertViewAppeared(events, index, expectedView, expectedParentId);
assertSessionId(expectedSessionId, expectedView);
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_TREE_APPEARING} event.
*/
public static void assertViewTreeStarted(@NonNull List<ContentCaptureEvent> events,
int index) {
assertSessionLevelEvent(events, index, TYPE_VIEW_TREE_APPEARING);
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_TREE_APPEARED} event.
*/
public static void assertViewTreeFinished(@NonNull List<ContentCaptureEvent> events,
int index) {
assertSessionLevelEvent(events, index, TYPE_VIEW_TREE_APPEARED);
}
private static void assertSessionLevelEvent(@NonNull List<ContentCaptureEvent> events,
int index, int expectedType) {
final ContentCaptureEvent event = getEvent(events, index, expectedType);
assertWithMessage("event %s (index %s) should not have a ViewNode", event, index)
.that(event.getViewNode()).isNull();
assertWithMessage("event %s (index %s) should not have text", event, index)
.that(event.getText()).isNull();
assertWithMessage("event %s (index %s) should not have an autofillId", event, index)
.that(event.getId()).isNull();
assertWithMessage("event %s (index %s) should not have autofillIds", event, index)
.that(event.getIds()).isNull();
}
/**
* Asserts the contents of a {@link #TYPE_SESSION_RESUMED} event.
*/
public static void assertSessionResumed(@NonNull List<ContentCaptureEvent> events,
int index) {
assertSessionLevelEvent(events, index, TYPE_SESSION_RESUMED);
}
/**
* Asserts the contents of a {@link #TYPE_SESSION_PAUSED} event.
*/
public static void assertSessionPaused(@NonNull List<ContentCaptureEvent> events,
int index) {
assertSessionLevelEvent(events, index, TYPE_SESSION_PAUSED);
}
/**
* Asserts that a session for the given activity has no view-level events, just
* {@link #TYPE_SESSION_RESUMED} and {@link #TYPE_SESSION_PAUSED}.
*/
public static void assertNoViewLevelEvents(@NonNull Session session,
@NonNull AbstractContentCaptureActivity activity) {
assertRightActivity(session, session.id, activity);
final List<ContentCaptureEvent> events = removeUnexpectedEvents(session.getEvents());
Log.v(TAG, "events on " + activity + ": " + events);
assertThat(events).hasSize(2);
assertSessionResumed(events, 0);
assertSessionPaused(events, 1);
}
/**
* This method is used to remove unexpected events if the test should only
* contain session level events.
* In special case, there are some events, such as {@link #TYPE_WINDOW_BOUNDS_CHANGED}
* and {@link #TYPE_VIEW_INSETS_CHANGED}, will be accidentally generated by
* the system. Because these events were not expected in the test, remove
* them if needed.
*/
public static List<ContentCaptureEvent> removeUnexpectedEvents(
@NonNull List<ContentCaptureEvent> events) {
return Collections.unmodifiableList(events).stream().filter(
e -> e.getType() != TYPE_WINDOW_BOUNDS_CHANGED
&& e.getType() != TYPE_VIEW_INSETS_CHANGED
&& e.getType() != TYPE_VIEW_TREE_APPEARING
&& e.getType() != TYPE_VIEW_TREE_APPEARED
).collect(Collectors.toList());
}
/** Gets a list of events that are related to view changes only. */
public static List<ContentCaptureEvent> getViewLevelEvents(
@NonNull List<ContentCaptureEvent> events) {
return Collections.unmodifiableList(events).stream().filter(
e -> e.getType() == TYPE_WINDOW_BOUNDS_CHANGED
|| e.getType() == TYPE_VIEW_INSETS_CHANGED
|| e.getType() == TYPE_VIEW_TREE_APPEARING
|| e.getType() == TYPE_VIEW_TREE_APPEARED
).collect(Collectors.toList());
}
/**
* Asserts that a session for the given activity has events at all.
*/
public static void assertNoEvents(@NonNull Session session,
@NonNull ComponentName componentName) {
assertRightActivity(session, session.id, componentName);
assertThat(session.getEvents()).isEmpty();
}
/**
* Asserts that the events received by the service optionally contains the
* {@code TYPE_VIEW_DISAPPEARED} events, as they might have not been generated if the views
* disappeared after the activity stopped.
*
* @param events events received by the service.
* @param minimumSize size of events received if activity stopped before views disappeared
* @param expectedIds ids of views that might have disappeared.
*
* @return whether the view disappeared events were generated
*/
// TODO(b/123540067, 122315042): remove this method if we could make it deterministic, and
// inline the assertions (or rename / change its logic)
public static boolean assertViewsOptionallyDisappeared(
@NonNull List<ContentCaptureEvent> events, int minimumSize,
@NonNull AutofillId... expectedIds) {
final int actualSize = events.size();
final int disappearedEventIndex;
if (actualSize == minimumSize) {
// Activity stopped before TYPE_VIEW_DISAPPEARED were sent.
return false;
} else if (actualSize == minimumSize + 1) {
// Activity did not receive TYPE_VIEW_TREE_APPEARING and TYPE_VIEW_TREE_APPEARED.
disappearedEventIndex = minimumSize;
} else {
disappearedEventIndex = minimumSize + 1;
}
final ContentCaptureEvent batchDisappearEvent = events.get(disappearedEventIndex);
if (expectedIds.length == 1) {
assertWithMessage("Should have just one deleted id on %s", batchDisappearEvent)
.that(batchDisappearEvent.getIds()).isNull();
assertWithMessage("wrong deleted id on %s", batchDisappearEvent)
.that(batchDisappearEvent.getId()).isEqualTo(expectedIds[0]);
} else {
assertWithMessage("Should not have individual deleted id on %s", batchDisappearEvent)
.that(batchDisappearEvent.getId()).isNull();
final List<AutofillId> actualIds = batchDisappearEvent.getIds();
assertWithMessage("wrong deleteds id on %s", batchDisappearEvent)
.that(actualIds).containsExactly((Object[]) expectedIds);
}
return true;
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event, without checking for parent
*/
public static void assertViewWithUnknownParentAppeared(
@NonNull List<ContentCaptureEvent> events, int index,
@NonNull ContentCaptureSessionId expectedSessionId, @NonNull View expectedView) {
assertViewWithUnknownParentAppeared(events, index, expectedView);
assertSessionId(expectedSessionId, expectedView);
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_DISAPPEARED} event for a single view.
*/
public static void assertViewDisappeared(@NonNull List<ContentCaptureEvent> events, int index,
@NonNull AutofillId expectedId) {
final ContentCaptureEvent event = assertCommonViewDisappearedProperties(events, index);
assertWithMessage("wrong autofillId on event %s (index %s)", event, index)
.that(event.getId()).isEqualTo(expectedId);
assertWithMessage("event %s (index %s) should not have autofillIds", event, index)
.that(event.getIds()).isNull();
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_DISAPPEARED} event for multiple views.
*/
public static void assertViewsDisappeared(@NonNull List<ContentCaptureEvent> events, int index,
@NonNull AutofillId... expectedIds) {
final ContentCaptureEvent event = assertCommonViewDisappearedProperties(events, index);
final List<AutofillId> ids = event.getIds();
assertWithMessage("no autofillIds on event %s (index %s)", event, index).that(ids)
.isNotNull();
assertWithMessage("wrong autofillId on event %s (index %s)", event, index)
.that(ids).containsExactly((Object[]) expectedIds).inOrder();
assertWithMessage("event %s (index %s) should not have autofillId", event, index)
.that(event.getId()).isNull();
}
private static ContentCaptureEvent assertCommonViewDisappearedProperties(
@NonNull List<ContentCaptureEvent> events, int index) {
final ContentCaptureEvent event = getEvent(events, index, TYPE_VIEW_DISAPPEARED);
assertWithMessage("event %s (index %s) should not have a ViewNode", event, index)
.that(event.getViewNode()).isNull();
assertWithMessage("event %s (index %s) should not have text", event, index)
.that(event.getText()).isNull();
return event;
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event for a virtual node.
*/
public static void assertVirtualViewAppeared(@NonNull List<ContentCaptureEvent> events,
int index, @NonNull ContentCaptureSession session, @NonNull AutofillId parentId,
int childId, @Nullable String expectedText) {
final ContentCaptureEvent event = getEvent(events, index, TYPE_VIEW_APPEARED);
final ViewNode node = event.getViewNode();
assertThat(node).isNotNull();
final AutofillId expectedId = session.newAutofillId(parentId, childId);
assertWithMessage("wrong autofill id on %s (index %s)", event, index)
.that(node.getAutofillId()).isEqualTo(expectedId);
if (expectedText != null) {
assertWithMessage("wrong text on %s(index %s) ", event, index)
.that(node.getText().toString()).isEqualTo(expectedText);
} else {
assertWithMessage("%s (index %s) should not have text", node, index)
.that(node.getText()).isNull();
}
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_DISAPPEARED} event for a virtual node.
*/
public static void assertVirtualViewDisappeared(@NonNull List<ContentCaptureEvent> events,
int index, @NonNull AutofillId parentId, @NonNull ContentCaptureSession session,
long childId) {
assertViewDisappeared(events, index, session.newAutofillId(parentId, childId));
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_DISAPPEARED} event for many virtual nodes.
*/
public static void assertVirtualViewsDisappeared(@NonNull List<ContentCaptureEvent> events,
int index, @NonNull AutofillId parentId, @NonNull ContentCaptureSession session,
long... childrenIds) {
final int size = childrenIds.length;
final AutofillId[] expectedIds = new AutofillId[size];
for (int i = 0; i < childrenIds.length; i++) {
expectedIds[i] = session.newAutofillId(parentId, childrenIds[i]);
}
assertViewsDisappeared(events, index, expectedIds);
}
/**
* Asserts a view has the given session id.
*/
public static void assertSessionId(@NonNull ContentCaptureSessionId expectedSessionId,
@NonNull View view) {
assertThat(expectedSessionId).isNotNull();
final ContentCaptureSession session = view.getContentCaptureSession();
assertWithMessage("no session for view %s", view).that(session).isNotNull();
assertWithMessage("wrong session id for for view %s", view)
.that(session.getContentCaptureSessionId()).isEqualTo(expectedSessionId);
}
/**
* Asserts the contents of a {@link #TYPE_VIEW_TEXT_CHANGED} event.
*/
public static void assertViewTextChanged(@NonNull List<ContentCaptureEvent> events, int index,
@NonNull AutofillId expectedId, @NonNull String expectedText) {
final ContentCaptureEvent event = getEvent(events, index, TYPE_VIEW_TEXT_CHANGED);
assertWithMessage("Wrong id on %s (%s)", event, index).that(event.getId())
.isEqualTo(expectedId);
assertWithMessage("Wrong text on %s (%s)", event, index).that(event.getText().toString())
.isEqualTo(expectedText);
}
/**
* Asserts the existence and contents of a {@link #TYPE_VIEW_INSETS_CHANGED} event.
*/
public static void assertViewInsetsChanged(@NonNull List<ContentCaptureEvent> events) {
boolean insetsEventFound = false;
for (ContentCaptureEvent event : events) {
if (event.getType() == TYPE_VIEW_INSETS_CHANGED) {
assertWithMessage("Expected view insets to be non-null on %s", event)
.that(event.getInsets()).isNotNull();
insetsEventFound = true;
}
}
if (!insetsEventFound) {
throw new RetryableException(
String.format(
"Expected at least one VIEW_INSETS_CHANGED event in the set of events %s",
events));
}
}
/**
* Asserts the existence and contents of a {@link #TYPE_WINDOW_BOUNDS_CHANGED} event.
*/
public static void assertWindowBoundsChanged(@NonNull List<ContentCaptureEvent> events) {
boolean boundsEventFound = false;
for (ContentCaptureEvent event : events) {
if (event.getType() == TYPE_WINDOW_BOUNDS_CHANGED) {
assertWithMessage("Expected window bounds to be non-null on %s", event)
.that(event.getBounds()).isNotNull();
boundsEventFound = true;
}
}
if (!boundsEventFound) {
throw new RetryableException(
String.format(
"Expected at least one WINDOW_BOUNDS_CHANGED event in the set of events %s",
events));
}
}
/**
* Asserts the basic contents of a {@link #TYPE_CONTEXT_UPDATED} event.
*/
public static ContentCaptureEvent assertContextUpdated(
@NonNull List<ContentCaptureEvent> events, int index) {
final ContentCaptureEvent event = getEvent(events, index, TYPE_CONTEXT_UPDATED);
assertWithMessage("event %s (index %s) should not have a ViewNode", event, index)
.that(event.getViewNode()).isNull();
assertWithMessage("event %s (index %s) should not have text", event, index)
.that(event.getViewNode()).isNull();
assertWithMessage("event %s (index %s) should not have an autofillId", event, index)
.that(event.getId()).isNull();
assertWithMessage("event %s (index %s) should not have autofillIds", event, index)
.that(event.getIds()).isNull();
return event;
}
/**
* Asserts the order a session was created or destroyed.
*/
public static void assertLifecycleOrder(int expectedOrder, @NonNull Session session,
@NonNull LifecycleOrder type) {
switch(type) {
case CREATION:
assertWithMessage("Wrong order of creation for session %s", session)
.that(session.creationOrder).isEqualTo(expectedOrder);
break;
case DESTRUCTION:
assertWithMessage("Wrong order of destruction for session %s", session)
.that(session.destructionOrder).isEqualTo(expectedOrder);
break;
default:
throw new IllegalArgumentException("Invalid type: " + type);
}
}
/**
* Gets the event at the given index, failing with the user-friendly message if necessary...
*/
@NonNull
private static ContentCaptureEvent getEvent(@NonNull List<ContentCaptureEvent> events,
int index, int expectedType) {
assertWithMessage("events is null").that(events).isNotNull();
final ContentCaptureEvent event = events.get(index);
assertWithMessage("no event at index %s (size %s): %s", index, events.size(), events)
.that(event).isNotNull();
final int actualType = event.getType();
if (actualType != expectedType) {
throw new AssertionError(String.format(
"wrong event type (expected %s, actual is %s) at index %s: %s",
eventTypeAsString(expectedType), eventTypeAsString(actualType), index, event));
}
assertWithMessage("invalid time on %s (index %s)", event, index).that(event.getEventTime())
.isAtLeast(MY_EPOCH);
return event;
}
/**
* Gets an user-friendly description of the given event type.
*/
@NonNull
public static String eventTypeAsString(int type) {
final String string;
switch (type) {
case TYPE_VIEW_APPEARED:
string = "APPEAR";
break;
case TYPE_VIEW_DISAPPEARED:
string = "DISAPPEAR";
break;
case TYPE_VIEW_TEXT_CHANGED:
string = "TEXT_CHANGE";
break;
case TYPE_VIEW_TREE_APPEARING:
string = "TREE_START";
break;
case TYPE_VIEW_TREE_APPEARED:
string = "TREE_END";
break;
case TYPE_SESSION_PAUSED:
string = "PAUSED";
break;
case TYPE_SESSION_RESUMED:
string = "RESUMED";
break;
case TYPE_WINDOW_BOUNDS_CHANGED:
string = "WINDOW_BOUNDS";
break;
default:
return "UNKNOWN-" + type;
}
return String.format("%s-%d", string, type);
}
private Assertions() {
throw new UnsupportedOperationException("contain static methods only");
}
public enum LifecycleOrder {
CREATION, DESTRUCTION
}
}