1 // Copyright 2023 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base.test.transit; 6 7 import android.view.View; 8 9 import org.hamcrest.Matcher; 10 11 import org.chromium.base.test.transit.ViewConditions.DisplayedCondition; 12 import org.chromium.base.test.transit.ViewConditions.DoesNotExistAnymoreCondition; 13 14 import java.util.ArrayList; 15 import java.util.List; 16 17 /** 18 * The elements that define a {@link ConditionalState}. 19 * 20 * <pre> 21 * - An ACTIVE ConditionalState is considered to have these elements available. 22 * - The presence of each element is an enter condition for the ConditionalState. 23 * - The absence of each element is an exit condition for the ConditionalState (except for unowned 24 * elements). 25 * </pre> 26 */ 27 public class Elements { 28 private final List<Condition> mEnterConditions; 29 private final List<Condition> mExitConditions; 30 31 /** Private constructor, instantiated by {@link Builder#build(ConditionalState)}. */ Elements(List<Condition> enterConditions, List<Condition> exitConditions)32 private Elements(List<Condition> enterConditions, List<Condition> exitConditions) { 33 mEnterConditions = enterConditions; 34 mExitConditions = exitConditions; 35 } 36 getEnterConditions()37 List<Condition> getEnterConditions() { 38 return mEnterConditions; 39 } 40 getExitConditions()41 List<Condition> getExitConditions() { 42 return mExitConditions; 43 } 44 45 /** 46 * Builder for {@link Elements}. 47 * 48 * <p>Passed to {@link ConditionalState#declareElements(Builder)}, which must declare the 49 * ConditionalState's elements by calling the declare___() methods. 50 */ 51 public static class Builder { 52 private ArrayList<ViewElement> mViewElements = new ArrayList<>(); 53 private ArrayList<Condition> mOtherEnterConditions = new ArrayList<>(); 54 private ArrayList<Condition> mOtherExitConditions = new ArrayList<>(); 55 Builder()56 Builder() {} 57 58 /** 59 * Declare as an element a single view that matches |viewMatcher| which will be gone after 60 * the ConditionalState is FINISHED. 61 */ declareView(Matcher<View> viewMatcher)62 public Builder declareView(Matcher<View> viewMatcher) { 63 declareView(viewMatcher, /* owned= */ true); 64 return this; 65 } 66 67 /** 68 * Declare as an element a single view that matches |viewMatcher| which will not necessarily 69 * be gone after the ConditionalState is FINISHED. 70 */ declareUnownedView(Matcher<View> viewMatcher)71 public Builder declareUnownedView(Matcher<View> viewMatcher) { 72 declareView(viewMatcher, /* owned= */ false); 73 return this; 74 } 75 declareView(Matcher<View> viewMatcher, boolean owned)76 private Builder declareView(Matcher<View> viewMatcher, boolean owned) { 77 mViewElements.add(new ViewElement(viewMatcher, owned)); 78 return this; 79 } 80 81 /** 82 * Declare as an element a generic enter Condition. It must remain true as long as the 83 * ConditionalState is ACTIVE. 84 */ declareEnterCondition(Condition condition)85 public Builder declareEnterCondition(Condition condition) { 86 mOtherEnterConditions.add(condition); 87 return this; 88 } 89 90 /** Declare as an element a generic exit Condition. */ declareExitCondition(Condition condition)91 public Builder declareExitCondition(Condition condition) { 92 mOtherExitConditions.add(condition); 93 return this; 94 } 95 96 /** 97 * Instantiates the {@link Elements} of a given |conditionalState| after they were declared 98 * by calling the Builder's declare___() methods. 99 */ build(ConditionalState conditionalState)100 Elements build(ConditionalState conditionalState) { 101 ArrayList<Condition> enterConditions = new ArrayList<>(); 102 ArrayList<Condition> exitConditions = new ArrayList<>(); 103 104 for (ViewElement viewElement : mViewElements) { 105 DisplayedCondition displayedCondition = 106 new DisplayedCondition(viewElement.mViewMatcher); 107 enterConditions.add(displayedCondition); 108 if (viewElement.mOwned) { 109 exitConditions.add( 110 new DoesNotExistAnymoreCondition( 111 viewElement.mViewMatcher, displayedCondition)); 112 } 113 } 114 115 enterConditions.addAll(mOtherEnterConditions); 116 exitConditions.addAll(mOtherExitConditions); 117 118 return new Elements(enterConditions, exitConditions); 119 } 120 } 121 122 private static class ViewElement { 123 private final Matcher<View> mViewMatcher; 124 private final boolean mOwned; 125 ViewElement(Matcher<View> viewMatcher, boolean owned)126 public ViewElement(Matcher<View> viewMatcher, boolean owned) { 127 mViewMatcher = viewMatcher; 128 mOwned = owned; 129 } 130 } 131 } 132