diff options
Diffstat (limited to 'lifecycle/lifecycle-extensions/src/androidTest/java/androidx')
10 files changed, 789 insertions, 96 deletions
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.kt b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/EmptyActivity.java index 6b0c8590369..33fd260b76b 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 00000000000..55bc682a8f2 --- /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 00000000000..ca3a8600ea1 --- /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 696c0c99b24..00000000000 --- 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 00000000000..4e38fe636db --- /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 00000000000..56ccb558914 --- /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 00000000000..66bf9eb2484 --- /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 00000000000..caf1a05daac --- /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/viewmodeltest/TestViewModel.java b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/viewmodeltest/TestViewModel.java new file mode 100644 index 00000000000..40c27b99566 --- /dev/null +++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/viewmodeltest/TestViewModel.java @@ -0,0 +1,28 @@ +/* + * 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.app.Application; + +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 00000000000..c20e819dfa7 --- /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); + } + } +} |