blob: 39ea6953d5b480a24599a82fba9d1a6fba86f925 [file] [log] [blame]
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.base.test.transit;
import androidx.annotation.Nullable;
import org.chromium.base.Log;
import java.util.ArrayList;
/**
* A {@link Transition} into a {@link TransitStation}, either from another TransitStation or as an
* entry point.
*/
public class Trip extends Transition {
private static final String TAG = "Transit";
private final int mId;
@Nullable private final TransitStation mOrigin;
private final TransitStation mDestination;
private static int sLastTripId;
private Trip(@Nullable TransitStation origin, TransitStation destination, Trigger trigger) {
super(trigger);
mOrigin = origin;
mDestination = destination;
mId = ++sLastTripId;
}
/**
* Starts a transition from a TransitStation to another (or from no TransitStation if at an
* entry point). Runs the transition |trigger|, and blocks until the destination TransitStation
* is considered ACTIVE (enter Conditions are fulfilled), the origin TransitStation is
* considered FINISHED (exit Conditions are fulfilled), and the Transition's conditions are
* fulfilled.
*
* @param origin the StationFacility to depart from, null if at an entry point.
* @param destination the StationFacility to arrive at.
* @param trigger the trigger to start the transition (e.g. clicking a view).
* @return the TransitStation entered.
* @param <T> the type of TransitStation entered.
*/
public static <T extends TransitStation> T travelSync(
@Nullable TransitStation origin, T destination, Trigger trigger) {
Trip trip = new Trip(origin, destination, trigger);
trip.travelSyncInternal();
return destination;
}
private void travelSyncInternal() {
embark();
if (mOrigin != null) {
Log.i(TAG, "Trip %d: Embarked at %s towards %s", mId, mOrigin, mDestination);
} else {
Log.i(TAG, "Trip %d: Starting at entry point %s", mId, mDestination);
}
triggerTransition();
Log.i(TAG, "Trip %d: Triggered transition, waiting to arrive at %s", mId, mDestination);
waitUntilArrival();
Log.i(TAG, "Trip %d: Arrived at %s", mId, mDestination);
PublicTransitConfig.maybePauseAfterTransition(mDestination);
}
private void embark() {
if (mOrigin != null) {
mOrigin.setStateTransitioningFrom();
}
mDestination.setStateTransitioningTo();
}
private void waitUntilArrival() {
ArrayList<ConditionWaiter.ConditionWaitStatus> waitStatuses = new ArrayList<>();
if (mOrigin != null) {
for (Condition condition : mOrigin.getExitConditions()) {
waitStatuses.add(
new ConditionWaiter.ConditionWaitStatus(
condition, ConditionWaiter.ConditionOrigin.EXIT));
}
for (Condition condition : mOrigin.getActiveFacilityExitConditions()) {
waitStatuses.add(
new ConditionWaiter.ConditionWaitStatus(
condition, ConditionWaiter.ConditionOrigin.EXIT));
}
}
for (Condition condition : mDestination.getEnterConditions()) {
waitStatuses.add(
new ConditionWaiter.ConditionWaitStatus(
condition, ConditionWaiter.ConditionOrigin.ENTER));
}
for (Condition condition : getTransitionConditions()) {
waitStatuses.add(
new ConditionWaiter.ConditionWaitStatus(
condition, ConditionWaiter.ConditionOrigin.TRANSITION));
}
// Throws CriteriaNotSatisfiedException if any conditions aren't met within the timeout and
// prints the state of all conditions. The timeout can be reduced when explicitly looking
// for flakiness due to tight timeouts.
try {
ConditionWaiter.waitFor(waitStatuses);
} catch (AssertionError e) {
throw new TravelException(mOrigin, mDestination, e);
}
if (mOrigin != null) {
mOrigin.setStateFinished();
}
mDestination.setStateActive();
TrafficControl.notifyActiveStationChanged(mDestination);
}
}