android.arch.lifecycle.TestUtils.java Source code

Java tutorial

Introduction

Here is the source code for android.arch.lifecycle.TestUtils.java

Source

/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.arch.lifecycle;

import static android.arch.lifecycle.Lifecycle.Event.ON_CREATE;
import static android.arch.lifecycle.Lifecycle.Event.ON_DESTROY;
import static android.arch.lifecycle.Lifecycle.Event.ON_PAUSE;
import static android.arch.lifecycle.Lifecycle.Event.ON_RESUME;
import static android.arch.lifecycle.Lifecycle.Event.ON_START;
import static android.arch.lifecycle.Lifecycle.Event.ON_STOP;
import static android.arch.lifecycle.Lifecycle.State.CREATED;
import static android.arch.lifecycle.Lifecycle.State.DESTROYED;
import static android.arch.lifecycle.Lifecycle.State.RESUMED;
import static android.arch.lifecycle.Lifecycle.State.STARTED;
import static android.arch.lifecycle.testapp.TestEvent.LIFECYCLE_EVENT;
import static android.arch.lifecycle.testapp.TestEvent.OWNER_CALLBACK;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import android.app.Activity;
import android.app.Instrumentation;
import android.app.Instrumentation.ActivityMonitor;
import android.arch.lifecycle.testapp.TestEvent;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.v4.util.Pair;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

class TestUtils {

    private static final long TIMEOUT_MS = 2000;

    @SuppressWarnings("unchecked")
    static <T extends Activity> T recreateActivity(final T activity, ActivityTestRule rule) throws Throwable {
        ActivityMonitor monitor = new ActivityMonitor(activity.getClass().getCanonicalName(), null, false);
        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
        instrumentation.addMonitor(monitor);
        rule.runOnUiThread(activity::recreate);
        T result;

        // this guarantee that we will reinstall monitor between notifications about onDestroy
        // and onCreate
        //noinspection SynchronizationOnLocalVariableOrMethodParameter
        synchronized (monitor) {
            do {
                // the documetation says "Block until an Activity is created
                // that matches this monitor." This statement is true, but there are some other
                // true statements like: "Block until an Activity is destoyed" or
                // "Block until an Activity is resumed"...

                // this call will release synchronization monitor's monitor
                result = (T) monitor.waitForActivityWithTimeout(TIMEOUT_MS);
                if (result == null) {
                    throw new RuntimeException("Timeout. Failed to recreate an activity");
                }
            } while (result == activity);
        }
        return result;
    }

    static void waitTillCreated(final LifecycleOwner owner, ActivityTestRule<?> activityRule) throws Throwable {
        waitTillState(owner, activityRule, CREATED);
    }

    static void waitTillStarted(final LifecycleOwner owner, ActivityTestRule<?> activityRule) throws Throwable {
        waitTillState(owner, activityRule, STARTED);
    }

    static void waitTillResumed(final LifecycleOwner owner, ActivityTestRule<?> activityRule) throws Throwable {
        waitTillState(owner, activityRule, RESUMED);
    }

    static void waitTillDestroyed(final LifecycleOwner owner, ActivityTestRule<?> activityRule) throws Throwable {
        waitTillState(owner, activityRule, DESTROYED);
    }

    static void waitTillState(final LifecycleOwner owner, ActivityTestRule<?> activityRule, Lifecycle.State state)
            throws Throwable {
        final CountDownLatch latch = new CountDownLatch(1);
        activityRule.runOnUiThread(() -> {
            Lifecycle.State currentState = owner.getLifecycle().getCurrentState();
            if (currentState == state) {
                latch.countDown();
            } else {
                owner.getLifecycle().addObserver(new LifecycleObserver() {
                    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
                    public void onStateChanged(LifecycleOwner provider) {
                        if (provider.getLifecycle().getCurrentState() == state) {
                            latch.countDown();
                            provider.getLifecycle().removeObserver(this);
                        }
                    }
                });
            }
        });
        boolean latchResult = latch.await(1, TimeUnit.MINUTES);
        assertThat("expected " + state + " never happened. Current state:" + owner.getLifecycle().getCurrentState(),
                latchResult, is(true));

        // wait for another loop to ensure all observers are called
        activityRule.runOnUiThread(() -> {
            // do nothing
        });
    }

    @SafeVarargs
    static <T> List<T> flatMap(List<T>... items) {
        ArrayList<T> result = new ArrayList<>();
        for (List<T> item : items) {
            result.addAll(item);
        }
        return result;
    }

    /**
     * Event tuples of {@link TestEvent} and {@link Lifecycle.Event}
     * in the order they should arrive.
     */
    @SuppressWarnings("unchecked")
    static class OrderedTuples {
        static final List<Pair<TestEvent, Lifecycle.Event>> CREATE = Arrays
                .asList(new Pair(OWNER_CALLBACK, ON_CREATE), new Pair(LIFECYCLE_EVENT, ON_CREATE));
        static final List<Pair<TestEvent, Lifecycle.Event>> START = Arrays
                .asList(new Pair(OWNER_CALLBACK, ON_START), new Pair(LIFECYCLE_EVENT, ON_START));
        static final List<Pair<TestEvent, Lifecycle.Event>> RESUME = Arrays
                .asList(new Pair(OWNER_CALLBACK, ON_RESUME), new Pair(LIFECYCLE_EVENT, ON_RESUME));
        static final List<Pair<TestEvent, Lifecycle.Event>> PAUSE = Arrays
                .asList(new Pair(LIFECYCLE_EVENT, ON_PAUSE), new Pair(OWNER_CALLBACK, ON_PAUSE));
        static final List<Pair<TestEvent, Lifecycle.Event>> STOP = Arrays.asList(new Pair(LIFECYCLE_EVENT, ON_STOP),
                new Pair(OWNER_CALLBACK, ON_STOP));
        static final List<Pair<TestEvent, Lifecycle.Event>> DESTROY = Arrays
                .asList(new Pair(LIFECYCLE_EVENT, ON_DESTROY), new Pair(OWNER_CALLBACK, ON_DESTROY));
    }
}