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>