[go: nahoru, domu]

Revert "Remove redundant lifecycle-extensions tests"

This reverts r.android.com/982005

Bug: 135942802
Test: ./gradlew bOS
Change-Id: Ifaa161d100e884ab93ae10cd746f38aca59871a1
diff --git a/lifecycle/lifecycle-extensions/build.gradle b/lifecycle/lifecycle-extensions/build.gradle
index 836cb93..00b20b0 100644
--- a/lifecycle/lifecycle-extensions/build.gradle
+++ b/lifecycle/lifecycle-extensions/build.gradle
@@ -23,7 +23,6 @@
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
-    id("kotlin-android")
 }
 
 dependencies {
@@ -41,15 +40,12 @@
     testImplementation(JUNIT)
     testImplementation(MOCKITO_CORE)
 
-    androidTestImplementation(KOTLIN_STDLIB)
-    androidTestImplementation(TRUTH)
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
     androidTestImplementation(ANDROIDX_TEST_RUNNER)
     androidTestImplementation(ANDROIDX_TEST_RULES)
     androidTestImplementation(ESPRESSO_CORE)
     androidTestImplementation(SUPPORT_APPCOMPAT, libs.support_exclude_config)
-    androidTestImplementation(project(":internal-testutils"))
 }
 
 androidx {
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/AndroidManifest.xml b/lifecycle/lifecycle-extensions/src/androidTest/AndroidManifest.xml
index 437b5b1..c66c06e 100644
--- a/lifecycle/lifecycle-extensions/src/androidTest/AndroidManifest.xml
+++ b/lifecycle/lifecycle-extensions/src/androidTest/AndroidManifest.xml
@@ -19,7 +19,13 @@
           package="androidx.lifecycle.extensions.test">
 
     <application>
+        <activity android:name="androidx.lifecycle.viewmodeltest.ViewModelActivity"
+                  android:theme="@style/Base.Theme.AppCompat">
+        </activity>
         <activity android:name="androidx.lifecycle.EmptyActivity"/>
+        <activity android:name="androidx.lifecycle.activity.FragmentLifecycleActivity"
+            android:theme="@style/Base.Theme.AppCompat"/>
+        <activity android:name="androidx.lifecycle.activity.EmptyActivity"/>
     </application>
 
 </manifest>
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.kt b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.java
similarity index 82%
rename from lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.kt
rename to lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.java
index 6b0c859..33fd260 100644
--- a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.kt
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.java
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-package androidx.lifecycle
+package androidx.lifecycle;
 
-import androidx.fragment.app.FragmentActivity
+import androidx.fragment.app.FragmentActivity;
 
-class EmptyActivity : FragmentActivity()
+public class EmptyActivity extends FragmentActivity {
+}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/FragmentLifecycleInActivityTest.java b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/FragmentLifecycleInActivityTest.java
new file mode 100644
index 0000000..55bc682
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/FragmentLifecycleInActivityTest.java
@@ -0,0 +1,156 @@
+/*
+ * 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 androidx.lifecycle;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
+import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.activity.FragmentLifecycleActivity;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+@RunWith(Parameterized.class)
+public class FragmentLifecycleInActivityTest {
+
+    private static final long TIMEOUT = 2; //sec
+
+    @Rule
+    public ActivityTestRule<FragmentLifecycleActivity> mActivityRule =
+            new ActivityTestRule<>(FragmentLifecycleActivity.class, false, false);
+
+    private Instrumentation mInstrumentation;
+
+    @SuppressWarnings("WeakerAccess")
+    @Parameterized.Parameter
+    public boolean mNested;
+
+    @Parameterized.Parameters(name = "nested_{0}")
+    public static Object[][] params() {
+        return new Object[][]{new Object[]{false}, new Object[]{true}};
+    }
+
+    @Before
+    public void getInstrumentation() {
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+    }
+
+    private void reset() {
+        mActivityRule.getActivity().resetEvents();
+    }
+
+    @Test
+    public void testFullEvents() throws Throwable {
+        final FragmentLifecycleActivity activity = launchActivity();
+        waitForIdle();
+        assertEvents(ON_CREATE, ON_START, ON_RESUME);
+        reset();
+        finishActivity(activity);
+        assertEvents(ON_PAUSE, ON_STOP, ON_DESTROY);
+    }
+
+    @Test
+    public void testStopStart() throws Throwable {
+        final FragmentLifecycleActivity activity = launchActivity();
+        waitForIdle();
+        assertEvents(ON_CREATE, ON_START, ON_RESUME);
+        reset();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mInstrumentation.callActivityOnPause(activity);
+                mInstrumentation.callActivityOnStop(activity);
+            }
+        });
+        waitForIdle();
+        assertEvents(ON_PAUSE, ON_STOP);
+        reset();
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mInstrumentation.callActivityOnStart(activity);
+                mInstrumentation.callActivityOnResume(activity);
+            }
+        });
+        waitForIdle();
+        assertEvents(ON_START, ON_RESUME);
+    }
+
+    private FragmentLifecycleActivity launchActivity() throws Throwable {
+        Intent intent = FragmentLifecycleActivity.intentFor(mInstrumentation.getTargetContext(),
+                mNested);
+        final FragmentLifecycleActivity activity = mActivityRule.launchActivity(intent);
+        mActivityRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                Fragment main = activity.getSupportFragmentManager()
+                        .findFragmentByTag(FragmentLifecycleActivity.MAIN_TAG);
+                assertThat("test sanity", main, notNullValue());
+                Fragment nestedFragment = main.getChildFragmentManager()
+                        .findFragmentByTag(FragmentLifecycleActivity.NESTED_TAG);
+                assertThat("test sanity", nestedFragment != null, is(mNested));
+            }
+        });
+        assertThat(activity.getObservedOwner(), instanceOf(
+                mNested ? FragmentLifecycleActivity.NestedFragment.class
+                        : FragmentLifecycleActivity.MainFragment.class
+        ));
+        return activity;
+    }
+
+    private void waitForIdle() {
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void finishActivity(final FragmentLifecycleActivity activity)
+            throws InterruptedException {
+        mInstrumentation.runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                activity.finish();
+            }
+        });
+        assertThat(activity.awaitForDestruction(TIMEOUT, TimeUnit.SECONDS), is(true));
+    }
+
+    private void assertEvents(Lifecycle.Event... events) {
+        assertThat(mActivityRule.getActivity().getLoggedEvents(), is(Arrays.asList(events)));
+    }
+}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/FragmentOperationsLifecycleTest.java b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/FragmentOperationsLifecycleTest.java
new file mode 100644
index 0000000..ca3a860
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/FragmentOperationsLifecycleTest.java
@@ -0,0 +1,120 @@
+/*
+ * 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 androidx.lifecycle;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_CREATE;
+import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import static java.util.Arrays.asList;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.activity.EmptyActivity;
+import androidx.lifecycle.extensions.test.R;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class FragmentOperationsLifecycleTest {
+
+    @Rule
+    public ActivityTestRule<EmptyActivity> mActivityTestRule = new ActivityTestRule<>(
+            EmptyActivity.class);
+
+    @Test
+    @UiThreadTest
+    public void addRemoveFragment() {
+        EmptyActivity activity = mActivityTestRule.getActivity();
+        Fragment fragment = new Fragment();
+        FragmentManager fm = activity.getSupportFragmentManager();
+        fm.beginTransaction().add(fragment, "tag").commitNow();
+        CollectingObserver observer = observeAndCollectIn(fragment);
+        assertThat(observer.getEventsAndReset(), is(asList(ON_CREATE, ON_START, ON_RESUME)));
+        fm.beginTransaction().remove(fragment).commitNow();
+        assertThat(observer.getEventsAndReset(), is(asList(ON_PAUSE, ON_STOP, ON_DESTROY)));
+        fm.beginTransaction().add(fragment, "tag").commitNow();
+        assertThat(observer.getEventsAndReset(), is(asList(ON_CREATE, ON_START, ON_RESUME)));
+    }
+
+    @Test
+    @UiThreadTest
+    public void fragmentInBackstack() {
+        EmptyActivity activity = mActivityTestRule.getActivity();
+        Fragment fragment1 = new Fragment();
+        FragmentManager fm = activity.getSupportFragmentManager();
+        fm.beginTransaction().add(R.id.fragment_container, fragment1, "tag").addToBackStack(null)
+                .commit();
+        fm.executePendingTransactions();
+        CollectingObserver observer1 = observeAndCollectIn(fragment1);
+        assertThat(observer1.getEventsAndReset(), is(asList(ON_CREATE, ON_START, ON_RESUME)));
+
+        Fragment fragment2 = new Fragment();
+        fm.beginTransaction().replace(R.id.fragment_container, fragment2).addToBackStack(null)
+                .commit();
+        fm.executePendingTransactions();
+
+        CollectingObserver observer2 = observeAndCollectIn(fragment2);
+        assertThat(observer1.getEventsAndReset(), is(asList(ON_PAUSE, ON_STOP)));
+        assertThat(observer2.getEventsAndReset(), is(asList(ON_CREATE, ON_START, ON_RESUME)));
+
+        assertThat(fm.popBackStackImmediate(), is(true));
+        assertThat(observer1.getEventsAndReset(), is(asList(ON_START, ON_RESUME)));
+        assertThat(observer2.getEventsAndReset(), is(asList(ON_PAUSE, ON_STOP, ON_DESTROY)));
+
+        assertThat(fm.popBackStackImmediate(), is(true));
+        assertThat(observer1.getEventsAndReset(), is(asList(ON_PAUSE, ON_STOP, ON_DESTROY)));
+    }
+
+    private static CollectingObserver observeAndCollectIn(Fragment fragment) {
+        CollectingObserver observer = new CollectingObserver();
+        fragment.getLifecycle().addObserver(observer);
+        return observer;
+    }
+
+    private static class CollectingObserver implements LifecycleEventObserver {
+        final List<Lifecycle.Event> mCollectedEvents = new ArrayList<>();
+
+        @Override
+        public void onStateChanged(@NonNull LifecycleOwner source, @NonNull Lifecycle.Event event) {
+            mCollectedEvents.add(event);
+        }
+
+        List<Lifecycle.Event> getEventsAndReset() {
+            ArrayList<Lifecycle.Event> events = new ArrayList<>(mCollectedEvents);
+            mCollectedEvents.clear();
+            return events;
+        }
+    }
+}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelProvidersFragmentTest.kt b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelProvidersFragmentTest.kt
deleted file mode 100644
index 696c0c9..0000000
--- a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelProvidersFragmentTest.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2019 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 androidx.lifecycle
-
-import androidx.fragment.app.Fragment
-import androidx.test.core.app.ActivityScenario
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.MediumTest
-import androidx.testutils.withActivity
-import com.google.common.truth.Truth.assertThat
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@MediumTest
-@RunWith(AndroidJUnit4::class)
-class ViewModelProvidersFragmentTest {
-    @Test
-    fun testViewModelProvidersActivity() {
-        with(ActivityScenario.launch(EmptyActivity::class.java)) {
-            val activityModel = withActivity {
-                ViewModelProviders.of(this).get(TestViewModel::class.java)
-            }
-            assertThat(activityModel).isNotNull()
-        }
-    }
-
-    @Test
-    fun testViewModelProvidersFragment() {
-        with(ActivityScenario.launch(EmptyActivity::class.java)) {
-            val fragmentModel = withActivity {
-                val fragment = Fragment()
-                supportFragmentManager.beginTransaction()
-                    .add(fragment, "tag")
-                    .commitNow()
-                ViewModelProviders.of(fragment).get(TestViewModel::class.java)
-            }
-            assertThat(fragmentModel).isNotNull()
-        }
-    }
-
-    @Test
-    fun testViewModelProvidersWithCustomFactoryActivity() {
-        val factory = CountingFactory()
-        with(ActivityScenario.launch(EmptyActivity::class.java)) {
-            val activityModel = withActivity {
-                ViewModelProviders.of(this, factory).get(TestViewModel::class.java)
-            }
-            assertThat(activityModel).isNotNull()
-            assertThat(factory.count).isEqualTo(1)
-        }
-    }
-
-    @Test
-    fun testViewModelProvidersWithCustomFactoryFragment() {
-        val factory = CountingFactory()
-        with(ActivityScenario.launch(EmptyActivity::class.java)) {
-            val fragmentModel = withActivity {
-                val fragment = Fragment()
-                supportFragmentManager.beginTransaction()
-                    .add(fragment, "tag")
-                    .commitNow()
-                ViewModelProviders.of(fragment, factory).get(TestViewModel::class.java)
-            }
-            assertThat(fragmentModel).isNotNull()
-            assertThat(factory.count).isEqualTo(1)
-        }
-    }
-
-    class CountingFactory : ViewModelProvider.NewInstanceFactory() {
-        var count = 0
-
-        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
-            count++
-            return super.create(modelClass)
-        }
-    }
-
-    class TestViewModel : ViewModel()
-}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelTest.java b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelTest.java
new file mode 100644
index 0000000..4e38fe6
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelTest.java
@@ -0,0 +1,176 @@
+/*
+ * 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 androidx.lifecycle;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import android.app.Instrumentation;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.lifecycle.viewmodeltest.TestViewModel;
+import androidx.lifecycle.viewmodeltest.ViewModelActivity;
+import androidx.lifecycle.viewmodeltest.ViewModelActivity.ViewModelFragment;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewModelTest {
+    private static final int TIMEOUT = 2; // secs
+
+    @Rule
+    public ActivityTestRule<ViewModelActivity> mActivityRule =
+            new ActivityTestRule<>(ViewModelActivity.class);
+
+    @Test
+    public void ensureSameViewHolders() throws Throwable {
+        final TestViewModel[] activityModel = new TestViewModel[1];
+        final TestViewModel[] defaultActivityModel = new TestViewModel[1];
+        final TestViewModel[] fragment1Model = new TestViewModel[1];
+        final TestViewModel[] fragment2Model = new TestViewModel[1];
+        final ViewModelActivity[] viewModelActivity = new ViewModelActivity[1];
+        viewModelActivity[0] = mActivityRule.getActivity();
+        mActivityRule.runOnUiThread(() -> {
+            ViewModelFragment fragment1 = getFragment(viewModelActivity[0],
+                    ViewModelActivity.FRAGMENT_TAG_1);
+            ViewModelFragment fragment2 = getFragment(viewModelActivity[0],
+                    ViewModelActivity.FRAGMENT_TAG_2);
+            assertThat(fragment1, notNullValue());
+            assertThat(fragment2, notNullValue());
+            assertThat(fragment1.activityModel, is(fragment2.activityModel));
+            assertThat(fragment1.fragmentModel, not(is(fragment2.activityModel)));
+            assertThat(mActivityRule.getActivity().activityModel, is(fragment1.activityModel));
+            activityModel[0] = mActivityRule.getActivity().activityModel;
+            defaultActivityModel[0] = mActivityRule.getActivity().defaultActivityModel;
+            assertThat(defaultActivityModel[0], not(is(activityModel[0])));
+            fragment1Model[0] = fragment1.fragmentModel;
+            fragment2Model[0] = fragment2.fragmentModel;
+        });
+        viewModelActivity[0] = recreateActivity();
+        mActivityRule.runOnUiThread(() -> {
+            ViewModelFragment fragment1 = getFragment(viewModelActivity[0],
+                    ViewModelActivity.FRAGMENT_TAG_1);
+            ViewModelFragment fragment2 = getFragment(viewModelActivity[0],
+                    ViewModelActivity.FRAGMENT_TAG_2);
+            assertThat(fragment1, notNullValue());
+            assertThat(fragment2, notNullValue());
+
+            assertThat(fragment1.activityModel, is(activityModel[0]));
+            assertThat(fragment2.activityModel, is(activityModel[0]));
+            assertThat(fragment1.fragmentModel, is(fragment1Model[0]));
+            assertThat(fragment2.fragmentModel, is(fragment2Model[0]));
+            assertThat(fragment1.defaultActivityModel, is(defaultActivityModel[0]));
+            assertThat(fragment2.defaultActivityModel, is(defaultActivityModel[0]));
+            assertThat(mActivityRule.getActivity().activityModel, is(activityModel[0]));
+            assertThat(mActivityRule.getActivity().defaultActivityModel,
+                    is(defaultActivityModel[0]));
+        });
+    }
+
+    @Test
+    @UiThreadTest
+    public void testGetApplication() {
+        TestViewModel activityModel = mActivityRule.getActivity().activityModel;
+        assertThat(activityModel.getApplication(),
+                is(ApplicationProvider.getApplicationContext().getApplicationContext()));
+    }
+
+    @Test
+    public void testOnClear() throws Throwable {
+        final ViewModelActivity activity = mActivityRule.getActivity();
+        final CountDownLatch latch = new CountDownLatch(1);
+        final LifecycleObserver observer = new DefaultLifecycleObserver() {
+            @Override
+            public void onResume(@NonNull LifecycleOwner owner) {
+                try {
+                    final FragmentManager manager = activity.getSupportFragmentManager();
+                    Fragment fragment = new Fragment();
+                    manager.beginTransaction().add(fragment, "temp").commitNow();
+                    ViewModel1 vm = ViewModelProviders.of(fragment).get(ViewModel1.class);
+                    assertThat(vm.mCleared, is(false));
+                    manager.beginTransaction().remove(fragment).commitNow();
+                    assertThat(vm.mCleared, is(true));
+                } finally {
+                    latch.countDown();
+                }
+            }
+        };
+
+        mActivityRule.runOnUiThread(() -> activity.getLifecycle().addObserver(observer));
+        assertThat(latch.await(TIMEOUT, TimeUnit.SECONDS), is(true));
+    }
+
+    private ViewModelFragment getFragment(FragmentActivity activity, String tag) {
+        return (ViewModelFragment) activity.getSupportFragmentManager()
+                .findFragmentByTag(tag);
+    }
+
+    private ViewModelActivity recreateActivity() throws Throwable {
+        Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(
+                ViewModelActivity.class.getCanonicalName(), null, false);
+        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+        instrumentation.addMonitor(monitor);
+        final ViewModelActivity previous = mActivityRule.getActivity();
+        mActivityRule.runOnUiThread(() -> previous.recreate());
+        ViewModelActivity result;
+
+        // this guarantee that we will reinstall monitor between notifications about onDestroy
+        // and onCreate
+        //noinspection SynchronizationOnLocalVariableOrMethodParameter
+        synchronized (monitor) {
+            do {
+                // the documentation 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 destroyed" or
+                // "Block until an Activity is resumed"...
+
+                // this call will release synchronization monitor's monitor
+                result = (ViewModelActivity) monitor.waitForActivityWithTimeout(4000);
+                if (result == null) {
+                    throw new RuntimeException("Timeout. Failed to recreate an activity");
+                }
+            } while (result == previous);
+        }
+        return result;
+    }
+
+    public static class ViewModel1 extends ViewModel {
+        boolean mCleared = false;
+
+        @Override
+        protected void onCleared() {
+            mCleared = true;
+        }
+    }
+}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelTestInTransaction.java b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelTestInTransaction.java
new file mode 100644
index 0000000..56ccb55
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelTestInTransaction.java
@@ -0,0 +1,94 @@
+/*
+ * 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 androidx.lifecycle;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.viewmodeltest.TestViewModel;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewModelTestInTransaction {
+
+    @Rule
+    public ActivityTestRule<EmptyActivity> mActivityRule =
+            new ActivityTestRule<>(EmptyActivity.class);
+
+    @Test
+    @UiThreadTest
+    public void testViewModelInTransactionActivity() {
+        EmptyActivity activity = mActivityRule.getActivity();
+        TestFragment fragment = new TestFragment();
+        activity.getSupportFragmentManager().beginTransaction().add(fragment, "tag").commitNow();
+        TestViewModel viewModel = ViewModelProviders.of(activity).get(TestViewModel.class);
+        assertThat(viewModel, is(fragment.mViewModel));
+    }
+
+    @Test
+    @UiThreadTest
+    public void testViewModelInTransactionFragment() {
+        EmptyActivity activity = mActivityRule.getActivity();
+        ParentFragment parent = new ParentFragment();
+        activity.getSupportFragmentManager().beginTransaction().add(parent, "parent").commitNow();
+        assertThat(parent.mExecuted, is(true));
+    }
+
+
+    public static class ParentFragment extends Fragment {
+
+        private boolean mExecuted;
+
+        @Override
+        public void onCreate(@Nullable Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            TestFragment fragment = new TestFragment();
+            getChildFragmentManager().beginTransaction().add(fragment, "tag").commitNow();
+            TestViewModel viewModel = ViewModelProviders.of(this).get(TestViewModel.class);
+            assertThat(viewModel, is(fragment.mViewModel));
+            mExecuted = true;
+        }
+    }
+
+    public static class TestFragment extends Fragment {
+
+        TestViewModel mViewModel;
+
+        @Override
+        public void onCreate(@Nullable Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            Fragment parentFragment = getParentFragment();
+            ViewModelProvider provider = parentFragment != null
+                    ? ViewModelProviders.of(parentFragment) : ViewModelProviders.of(getActivity());
+            mViewModel = provider.get(TestViewModel.class);
+            assertThat(mViewModel, notNullValue());
+        }
+    }
+}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/activity/EmptyActivity.java b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/activity/EmptyActivity.java
new file mode 100644
index 0000000..66bf9eb
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/activity/EmptyActivity.java
@@ -0,0 +1,31 @@
+/*
+ * 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 androidx.lifecycle.activity;
+
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.extensions.test.R;
+
+public class EmptyActivity extends FragmentActivity {
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+    }
+}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/activity/FragmentLifecycleActivity.java b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/activity/FragmentLifecycleActivity.java
new file mode 100644
index 0000000..caf1a05
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/activity/FragmentLifecycleActivity.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 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 androidx.lifecycle.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleEventObserver;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.extensions.test.R;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class FragmentLifecycleActivity extends AppCompatActivity {
+    public static final String NESTED_TAG = "nested_fragment";
+    public static final String MAIN_TAG = "main_fragment";
+    private static final String EXTRA_NESTED = "nested";
+
+    private final List<Lifecycle.Event> mLoggedEvents = Collections
+            .synchronizedList(new ArrayList<>());
+    private LifecycleOwner mObservedOwner;
+    private final CountDownLatch mDestroyLatch = new CountDownLatch(1);
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+        MainFragment fragment;
+        fragment = new MainFragment();
+        boolean nested = getIntent().getBooleanExtra(EXTRA_NESTED, false);
+        if (nested) {
+            fragment.mNestedFragment = new NestedFragment();
+        }
+        observe(nested ? fragment.mNestedFragment : fragment);
+        getSupportFragmentManager().beginTransaction()
+                .add(R.id.fragment_container, fragment, MAIN_TAG)
+                .commit();
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mDestroyLatch.countDown();
+    }
+
+    public void resetEvents() {
+        mLoggedEvents.clear();
+    }
+
+    public static class MainFragment extends Fragment {
+        @Nullable
+        Fragment mNestedFragment;
+
+        @Override
+        public void onCreate(@Nullable Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            if (mNestedFragment != null) {
+                getChildFragmentManager().beginTransaction()
+                        .add(mNestedFragment, NESTED_TAG)
+                        .commit();
+            }
+        }
+    }
+
+    public static class NestedFragment extends Fragment {
+    }
+
+    public static Intent intentFor(Context context, boolean nested) {
+        Intent intent = new Intent(context, FragmentLifecycleActivity.class);
+        intent.putExtra(EXTRA_NESTED, nested);
+        return intent;
+    }
+
+    public void observe(LifecycleOwner provider) {
+        mObservedOwner = provider;
+        provider.getLifecycle().addObserver(
+                (LifecycleEventObserver) (source, event) -> mLoggedEvents.add(event));
+    }
+
+    public List<Lifecycle.Event> getLoggedEvents() {
+        return mLoggedEvents;
+    }
+
+    public LifecycleOwner getObservedOwner() {
+        return mObservedOwner;
+    }
+
+    public boolean awaitForDestruction(long timeout, TimeUnit timeUnit)
+            throws InterruptedException {
+        return mDestroyLatch.await(timeout, timeUnit);
+    }
+}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.kt b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/viewmodeltest/TestViewModel.java
similarity index 63%
copy from lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.kt
copy to lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/viewmodeltest/TestViewModel.java
index 6b0c859..40c27b9 100644
--- a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.kt
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/viewmodeltest/TestViewModel.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,8 +14,15 @@
  * limitations under the License.
  */
 
-package androidx.lifecycle
+package androidx.lifecycle.viewmodeltest;
 
-import androidx.fragment.app.FragmentActivity
+import android.app.Application;
 
-class EmptyActivity : FragmentActivity()
+import androidx.lifecycle.AndroidViewModel;
+
+public class TestViewModel extends AndroidViewModel {
+
+    public TestViewModel(Application application) {
+        super(application);
+    }
+}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/viewmodeltest/ViewModelActivity.java b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/viewmodeltest/ViewModelActivity.java
new file mode 100644
index 0000000..c20e819
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/viewmodeltest/ViewModelActivity.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 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 androidx.lifecycle.viewmodeltest;
+
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.lifecycle.ViewModelProviders;
+import androidx.lifecycle.extensions.test.R;
+
+public class ViewModelActivity extends FragmentActivity {
+    public static final String KEY_FRAGMENT_MODEL = "fragment-model";
+    public static final String KEY_ACTIVITY_MODEL = "activity-model";
+    public static final String FRAGMENT_TAG_1 = "f1";
+    public static final String FRAGMENT_TAG_2 = "f2";
+
+    public TestViewModel activityModel;
+    public TestViewModel defaultActivityModel;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_view_model);
+        if (savedInstanceState == null) {
+            getSupportFragmentManager().beginTransaction()
+                    .add(R.id.fragment_container, new ViewModelFragment(), FRAGMENT_TAG_1)
+                    .add(new ViewModelFragment(), FRAGMENT_TAG_2)
+                    .commit();
+        }
+        activityModel = ViewModelProviders.of(this).get(KEY_ACTIVITY_MODEL, TestViewModel.class);
+        defaultActivityModel = ViewModelProviders.of(this).get(TestViewModel.class);
+    }
+
+    public static class ViewModelFragment extends Fragment {
+        public TestViewModel fragmentModel;
+        public TestViewModel activityModel;
+        public TestViewModel defaultActivityModel;
+
+        @Override
+        public void onCreate(@Nullable Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            fragmentModel = ViewModelProviders.of(this).get(KEY_FRAGMENT_MODEL,
+                    TestViewModel.class);
+            activityModel = ViewModelProviders.of(getActivity()).get(KEY_ACTIVITY_MODEL,
+                    TestViewModel.class);
+            defaultActivityModel = ViewModelProviders.of(getActivity()).get(TestViewModel.class);
+        }
+    }
+}
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/res/layout/activity_main.xml b/lifecycle/lifecycle-extensions/src/androidTest/res/layout/activity_main.xml
new file mode 100644
index 0000000..86730b2
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/src/androidTest/res/layout/activity_main.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 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.
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/activity_main"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context="androidx.lifecycle.activity.FragmentLifecycleActivity">
+    <FrameLayout android:id="@+id/fragment_container"
+                 android:layout_width="match_parent"
+                 android:layout_height="match_parent"></FrameLayout>
+</RelativeLayout>
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/res/layout/activity_view_model.xml b/lifecycle/lifecycle-extensions/src/androidTest/res/layout/activity_view_model.xml
new file mode 100644
index 0000000..eace2e9
--- /dev/null
+++ b/lifecycle/lifecycle-extensions/src/androidTest/res/layout/activity_view_model.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 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.
+  -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <FrameLayout android:id="@+id/fragment_container"
+                 android:layout_width="match_parent"
+                 android:layout_height="match_parent"></FrameLayout>
+</RelativeLayout>