1/*
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 android.arch.lifecycle;
18
19import static android.arch.lifecycle.Lifecycle.State.RESUMED;
20
21import android.app.Activity;
22import android.app.Instrumentation;
23import android.app.Instrumentation.ActivityMonitor;
24import android.support.test.InstrumentationRegistry;
25import android.support.test.rule.ActivityTestRule;
26
27import java.util.concurrent.CountDownLatch;
28
29public class TestUtils {
30
31    private static final long TIMEOUT_MS = 2000;
32
33    @SuppressWarnings("unchecked")
34    public static <T extends Activity> T recreateActivity(final T activity, ActivityTestRule rule)
35            throws Throwable {
36        ActivityMonitor monitor = new ActivityMonitor(
37                activity.getClass().getCanonicalName(), null, false);
38        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
39        instrumentation.addMonitor(monitor);
40        rule.runOnUiThread(activity::recreate);
41        T result;
42
43        // this guarantee that we will reinstall monitor between notifications about onDestroy
44        // and onCreate
45        //noinspection SynchronizationOnLocalVariableOrMethodParameter
46        synchronized (monitor) {
47            do {
48                // the documetation says "Block until an Activity is created
49                // that matches this monitor." This statement is true, but there are some other
50                // true statements like: "Block until an Activity is destoyed" or
51                // "Block until an Activity is resumed"...
52
53                // this call will release synchronization monitor's monitor
54                result = (T) monitor.waitForActivityWithTimeout(TIMEOUT_MS);
55                if (result == null) {
56                    throw new RuntimeException("Timeout. Failed to recreate an activity");
57                }
58            } while (result == activity);
59        }
60        return result;
61    }
62
63    static void waitTillResumed(final LifecycleActivity a, ActivityTestRule<?> activityRule)
64            throws Throwable {
65        final CountDownLatch latch = new CountDownLatch(1);
66        activityRule.runOnUiThread(() -> {
67            Lifecycle.State currentState = a.getLifecycle().getCurrentState();
68            if (currentState == RESUMED) {
69                latch.countDown();
70            }
71            a.getLifecycle().addObserver(new LifecycleObserver() {
72                @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
73                public void onStateChanged(LifecycleOwner provider) {
74                    latch.countDown();
75                    provider.getLifecycle().removeObserver(this);
76                }
77            });
78        });
79        latch.await();
80    }
81
82}
83