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