blob: 2045181260a2b81e27f59c40b79683b391d53fe6 [file] [log] [blame]
Justin Klaassen4d01eea2018-04-03 23:21:57 -04001/*
2 * Copyright (C) 2017 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
17package androidx.lifecycle;
18
19import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
20import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
21import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
22import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
23import static androidx.lifecycle.Lifecycle.Event.ON_START;
24import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
25import static androidx.lifecycle.Lifecycle.State.CREATED;
26import static androidx.lifecycle.Lifecycle.State.DESTROYED;
27import static androidx.lifecycle.Lifecycle.State.RESUMED;
28import static androidx.lifecycle.Lifecycle.State.STARTED;
29import static androidx.lifecycle.testapp.TestEvent.LIFECYCLE_EVENT;
30import static androidx.lifecycle.testapp.TestEvent.OWNER_CALLBACK;
31
32import static org.hamcrest.CoreMatchers.is;
33import static org.hamcrest.MatcherAssert.assertThat;
34
35import android.app.Activity;
36import android.app.Instrumentation;
37import android.app.Instrumentation.ActivityMonitor;
38import android.support.test.InstrumentationRegistry;
39import android.support.test.rule.ActivityTestRule;
40
41import androidx.core.util.Pair;
42import androidx.lifecycle.testapp.TestEvent;
43
44import java.util.ArrayList;
45import java.util.Arrays;
46import java.util.List;
47import java.util.concurrent.CountDownLatch;
48import java.util.concurrent.TimeUnit;
49
50class TestUtils {
51
52 private static final long TIMEOUT_MS = 2000;
53
54 @SuppressWarnings("unchecked")
55 static <T extends Activity> T recreateActivity(final T activity, ActivityTestRule rule)
56 throws Throwable {
57 ActivityMonitor monitor = new ActivityMonitor(
58 activity.getClass().getCanonicalName(), null, false);
59 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
60 instrumentation.addMonitor(monitor);
61 rule.runOnUiThread(activity::recreate);
62 T result;
63
64 // this guarantee that we will reinstall monitor between notifications about onDestroy
65 // and onCreate
66 //noinspection SynchronizationOnLocalVariableOrMethodParameter
67 synchronized (monitor) {
68 do {
69 // the documetation says "Block until an Activity is created
70 // that matches this monitor." This statement is true, but there are some other
71 // true statements like: "Block until an Activity is destoyed" or
72 // "Block until an Activity is resumed"...
73
74 // this call will release synchronization monitor's monitor
75 result = (T) monitor.waitForActivityWithTimeout(TIMEOUT_MS);
76 if (result == null) {
77 throw new RuntimeException("Timeout. Failed to recreate an activity");
78 }
79 } while (result == activity);
80 }
81 return result;
82 }
83
84 static void waitTillCreated(final LifecycleOwner owner, ActivityTestRule<?> activityRule)
85 throws Throwable {
86 waitTillState(owner, activityRule, CREATED);
87 }
88
89 static void waitTillStarted(final LifecycleOwner owner, ActivityTestRule<?> activityRule)
90 throws Throwable {
91 waitTillState(owner, activityRule, STARTED);
92 }
93
94 static void waitTillResumed(final LifecycleOwner owner, ActivityTestRule<?> activityRule)
95 throws Throwable {
96 waitTillState(owner, activityRule, RESUMED);
97 }
98
99 static void waitTillDestroyed(final LifecycleOwner owner, ActivityTestRule<?> activityRule)
100 throws Throwable {
101 waitTillState(owner, activityRule, DESTROYED);
102 }
103
104 static void waitTillState(final LifecycleOwner owner, ActivityTestRule<?> activityRule,
105 Lifecycle.State state)
106 throws Throwable {
107 final CountDownLatch latch = new CountDownLatch(1);
108 activityRule.runOnUiThread(() -> {
109 Lifecycle.State currentState = owner.getLifecycle().getCurrentState();
110 if (currentState == state) {
111 latch.countDown();
112 } else {
113 owner.getLifecycle().addObserver(new LifecycleObserver() {
114 @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
115 public void onStateChanged(LifecycleOwner provider) {
116 if (provider.getLifecycle().getCurrentState() == state) {
117 latch.countDown();
118 provider.getLifecycle().removeObserver(this);
119 }
120 }
121 });
122 }
123 });
124 boolean latchResult = latch.await(1, TimeUnit.MINUTES);
125 assertThat("expected " + state + " never happened. Current state:"
126 + owner.getLifecycle().getCurrentState(), latchResult, is(true));
127
128 // wait for another loop to ensure all observers are called
129 activityRule.runOnUiThread(() -> {
130 // do nothing
131 });
132 }
133
134 @SafeVarargs
135 static <T> List<T> flatMap(List<T>... items) {
136 ArrayList<T> result = new ArrayList<>();
137 for (List<T> item : items) {
138 result.addAll(item);
139 }
140 return result;
141 }
142
143 /**
144 * Event tuples of {@link TestEvent} and {@link Lifecycle.Event}
145 * in the order they should arrive.
146 */
147 @SuppressWarnings("unchecked")
148 static class OrderedTuples {
149 static final List<Pair<TestEvent, Lifecycle.Event>> CREATE =
150 Arrays.asList(new Pair(OWNER_CALLBACK, ON_CREATE),
151 new Pair(LIFECYCLE_EVENT, ON_CREATE));
152 static final List<Pair<TestEvent, Lifecycle.Event>> START =
153 Arrays.asList(new Pair(OWNER_CALLBACK, ON_START),
154 new Pair(LIFECYCLE_EVENT, ON_START));
155 static final List<Pair<TestEvent, Lifecycle.Event>> RESUME =
156 Arrays.asList(new Pair(OWNER_CALLBACK, ON_RESUME),
157 new Pair(LIFECYCLE_EVENT, ON_RESUME));
158 static final List<Pair<TestEvent, Lifecycle.Event>> PAUSE =
159 Arrays.asList(new Pair(LIFECYCLE_EVENT, ON_PAUSE),
160 new Pair(OWNER_CALLBACK, ON_PAUSE));
161 static final List<Pair<TestEvent, Lifecycle.Event>> STOP =
162 Arrays.asList(new Pair(LIFECYCLE_EVENT, ON_STOP),
163 new Pair(OWNER_CALLBACK, ON_STOP));
164 static final List<Pair<TestEvent, Lifecycle.Event>> DESTROY =
165 Arrays.asList(new Pair(LIFECYCLE_EVENT, ON_DESTROY),
166 new Pair(OWNER_CALLBACK, ON_DESTROY));
167 }
168}