• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.autofillservice.cts;
17 
18 import android.util.ArraySet;
19 import android.util.Log;
20 
21 import androidx.annotation.GuardedBy;
22 import androidx.annotation.NonNull;
23 import androidx.annotation.Nullable;
24 
25 import com.android.compatibility.common.util.TestNameUtils;
26 
27 import org.junit.rules.TestWatcher;
28 import org.junit.runner.Description;
29 
30 import java.util.Set;
31 
32 /**
33  * Custom {@link TestWatcher} that's the outer rule of all {@link AutoFillServiceTestCase} tests.
34  *
35  * <p>This class is not thread safe, but should be fine...
36  */
37 public final class AutofillTestWatcher extends TestWatcher {
38 
39     private static final String TAG = "AutofillTestWatcher";
40 
41     @GuardedBy("sUnfinishedBusiness")
42     private static final Set<AbstractAutoFillActivity> sUnfinishedBusiness = new ArraySet<>();
43 
44     @GuardedBy("sAllActivities")
45     private static final Set<AbstractAutoFillActivity> sAllActivities = new ArraySet<>();
46 
47     @Override
starting(Description description)48     protected void starting(Description description) {
49         resetStaticState();
50         final String testName = description.getDisplayName();
51         Log.i(TAG, "Starting " + testName);
52         TestNameUtils.setCurrentTestName(testName);
53     }
54 
55     @Override
finished(Description description)56     protected void finished(Description description) {
57         final String testName = description.getDisplayName();
58         try {
59             finishActivities();
60             waitUntilAllDestroyed();
61         } finally {
62             resetStaticState();
63         }
64         Log.i(TAG, "Finished " + testName);
65         TestNameUtils.setCurrentTestName(null);
66     }
67 
resetStaticState()68     private void resetStaticState() {
69         synchronized (sUnfinishedBusiness) {
70             sUnfinishedBusiness.clear();
71         }
72         synchronized (sAllActivities) {
73             sAllActivities.clear();
74         }
75     }
76 
77     /**
78      * Registers an activity so it's automatically finished (if necessary) after the test.
79      */
registerActivity(@onNull String where, @NonNull AbstractAutoFillActivity activity)80     public static void registerActivity(@NonNull String where,
81             @NonNull AbstractAutoFillActivity activity) {
82         synchronized (sUnfinishedBusiness) {
83             if (sUnfinishedBusiness.contains(activity)) {
84                 throw new IllegalStateException("Already registered " + activity);
85             }
86             Log.v(TAG, "registering activity on " + where + ": " + activity);
87             sUnfinishedBusiness.add(activity);
88             sAllActivities.add(activity);
89         }
90         synchronized (sAllActivities) {
91             sAllActivities.add(activity);
92 
93         }
94     }
95 
96     /**
97      * Unregisters an activity so it's not automatically finished after the test.
98      */
unregisterActivity(@onNull String where, @NonNull AbstractAutoFillActivity activity)99     public static void unregisterActivity(@NonNull String where,
100             @NonNull AbstractAutoFillActivity activity) {
101         synchronized (sUnfinishedBusiness) {
102             final boolean unregistered = sUnfinishedBusiness.remove(activity);
103             if (unregistered) {
104                 Log.d(TAG, "unregistered activity on " + where + ": " + activity);
105             } else {
106                 Log.v(TAG, "ignoring already unregistered activity on " + where + ": " + activity);
107             }
108         }
109     }
110 
111     /**
112      * Gets the instance of a previously registered activity.
113      */
114     @Nullable
getActivity(@onNull Class<A> clazz)115     public static <A extends AbstractAutoFillActivity> A getActivity(@NonNull Class<A> clazz) {
116         @SuppressWarnings("unchecked")
117         final A activity = (A) sAllActivities.stream().filter(a -> a.getClass().equals(clazz))
118                 .findFirst()
119                 .get();
120         return activity;
121     }
122 
finishActivities()123     private void finishActivities() {
124         synchronized (sUnfinishedBusiness) {
125             if (sUnfinishedBusiness.isEmpty()) {
126                 return;
127             }
128             Log.d(TAG, "Manually finishing " + sUnfinishedBusiness.size() + " activities");
129             for (AbstractAutoFillActivity activity : sUnfinishedBusiness) {
130                 if (activity.isFinishing()) {
131                     Log.v(TAG, "Ignoring activity that isFinishing(): " + activity);
132                 } else {
133                     Log.d(TAG, "Finishing activity: " + activity);
134                     activity.finishOnly();
135                 }
136             }
137         }
138     }
139 
waitUntilAllDestroyed()140     private void waitUntilAllDestroyed() {
141         synchronized (sAllActivities) {
142             if (sAllActivities.isEmpty()) return;
143 
144             Log.d(TAG, "Waiting until " + sAllActivities.size() + " activities are destroyed");
145             for (AbstractAutoFillActivity activity : sAllActivities) {
146                 Log.d(TAG, "Waiting for " + activity);
147                 try {
148                     activity.waintUntilDestroyed(Timeouts.ACTIVITY_RESURRECTION);
149                 } catch (InterruptedException e) {
150                     Log.e(TAG, "interrupted waiting for " + activity + " to be destroyed");
151                     Thread.currentThread().interrupt();
152                 }
153             }
154         }
155     }
156 }
157