1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.lifecycle; 18 19 import static org.hamcrest.CoreMatchers.is; 20 import static org.hamcrest.MatcherAssert.assertThat; 21 22 import android.app.Instrumentation; 23 import android.content.Intent; 24 import android.os.Build; 25 import android.support.test.InstrumentationRegistry; 26 import android.support.test.filters.SdkSuppress; 27 import android.support.test.filters.SmallTest; 28 import android.support.test.rule.ActivityTestRule; 29 import android.support.test.runner.AndroidJUnit4; 30 31 import androidx.fragment.app.FragmentActivity; 32 import androidx.lifecycle.testapp.CollectingSupportActivity; 33 import androidx.lifecycle.testapp.CollectingSupportFragment; 34 import androidx.lifecycle.testapp.NavigationDialogActivity; 35 36 import org.junit.Rule; 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 import java.util.concurrent.atomic.AtomicInteger; 41 42 @SmallTest 43 @RunWith(AndroidJUnit4.class) 44 public class LiveDataOnSaveInstanceStateTest { 45 @Rule 46 public ActivityTestRule<CollectingSupportActivity> mActivityTestRule = 47 new ActivityTestRule<>(CollectingSupportActivity.class); 48 49 @Test 50 @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.M) 51 public void liveData_partiallyObscuredActivity_maxSdkM() throws Throwable { 52 CollectingSupportActivity activity = mActivityTestRule.getActivity(); 53 54 liveData_partiallyObscuredLifecycleOwner_maxSdkM(activity); 55 } 56 57 @Test 58 @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.M) 59 public void liveData_partiallyObscuredActivityWithFragment_maxSdkM() throws Throwable { 60 CollectingSupportActivity activity = mActivityTestRule.getActivity(); 61 CollectingSupportFragment fragment = new CollectingSupportFragment(); 62 mActivityTestRule.runOnUiThread(() -> activity.replaceFragment(fragment)); 63 64 liveData_partiallyObscuredLifecycleOwner_maxSdkM(fragment); 65 } 66 67 @Test 68 @SdkSuppress(maxSdkVersion = Build.VERSION_CODES.M) 69 public void liveData_partiallyObscuredActivityFragmentInFragment_maxSdkM() throws Throwable { 70 CollectingSupportActivity activity = mActivityTestRule.getActivity(); 71 CollectingSupportFragment fragment = new CollectingSupportFragment(); 72 CollectingSupportFragment fragment2 = new CollectingSupportFragment(); 73 mActivityTestRule.runOnUiThread(() -> { 74 activity.replaceFragment(fragment); 75 fragment.replaceFragment(fragment2); 76 }); 77 78 liveData_partiallyObscuredLifecycleOwner_maxSdkM(fragment2); 79 } 80 81 @Test 82 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) 83 public void liveData_partiallyObscuredActivity_minSdkN() throws Throwable { 84 CollectingSupportActivity activity = mActivityTestRule.getActivity(); 85 86 liveData_partiallyObscuredLifecycleOwner_minSdkN(activity); 87 } 88 89 @Test 90 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) 91 public void liveData_partiallyObscuredActivityWithFragment_minSdkN() throws Throwable { 92 CollectingSupportActivity activity = mActivityTestRule.getActivity(); 93 CollectingSupportFragment fragment = new CollectingSupportFragment(); 94 mActivityTestRule.runOnUiThread(() -> activity.replaceFragment(fragment)); 95 96 liveData_partiallyObscuredLifecycleOwner_minSdkN(fragment); 97 } 98 99 @Test 100 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.N) 101 public void liveData_partiallyObscuredActivityFragmentInFragment_minSdkN() throws Throwable { 102 CollectingSupportActivity activity = mActivityTestRule.getActivity(); 103 CollectingSupportFragment fragment = new CollectingSupportFragment(); 104 CollectingSupportFragment fragment2 = new CollectingSupportFragment(); 105 mActivityTestRule.runOnUiThread(() -> { 106 activity.replaceFragment(fragment); 107 fragment.replaceFragment(fragment2); 108 }); 109 110 liveData_partiallyObscuredLifecycleOwner_minSdkN(fragment2); 111 } 112 113 private void liveData_partiallyObscuredLifecycleOwner_maxSdkM(LifecycleOwner lifecycleOwner) 114 throws Throwable { 115 final AtomicInteger atomicInteger = new AtomicInteger(0); 116 MutableLiveData<Integer> mutableLiveData = new MutableLiveData<>(); 117 mActivityTestRule.runOnUiThread(() -> mutableLiveData.setValue(0)); 118 119 TestUtils.waitTillResumed(lifecycleOwner, mActivityTestRule); 120 mActivityTestRule.runOnUiThread(() -> 121 mutableLiveData.observe(lifecycleOwner, atomicInteger::set)); 122 123 final FragmentActivity dialogActivity = launchDialog(); 124 125 TestUtils.waitTillCreated(lifecycleOwner, mActivityTestRule); 126 127 // Change the LiveData value and assert that the observer is not called given that the 128 // lifecycle is in the CREATED state. 129 mActivityTestRule.runOnUiThread(() -> mutableLiveData.setValue(1)); 130 assertThat(atomicInteger.get(), is(0)); 131 132 // Finish the dialog Activity, wait for the main activity to be resumed, and assert that 133 // the observer's onChanged method is called. 134 mActivityTestRule.runOnUiThread(dialogActivity::finish); 135 TestUtils.waitTillResumed(lifecycleOwner, mActivityTestRule); 136 assertThat(atomicInteger.get(), is(1)); 137 } 138 139 private void liveData_partiallyObscuredLifecycleOwner_minSdkN(LifecycleOwner lifecycleOwner) 140 throws Throwable { 141 final AtomicInteger atomicInteger = new AtomicInteger(0); 142 MutableLiveData<Integer> mutableLiveData = new MutableLiveData<>(); 143 mActivityTestRule.runOnUiThread(() -> mutableLiveData.setValue(0)); 144 145 TestUtils.waitTillResumed(lifecycleOwner, mActivityTestRule); 146 147 mActivityTestRule.runOnUiThread(() -> 148 mutableLiveData.observe(lifecycleOwner, atomicInteger::set)); 149 150 // Launch the NavigationDialogActivity, partially obscuring the activity, and wait for the 151 // lifecycleOwner to hit onPause (or enter the STARTED state). On API 24 and above, this 152 // onPause should be the last lifecycle method called (and the STARTED state should be the 153 // final resting state). 154 launchDialog(); 155 TestUtils.waitTillStarted(lifecycleOwner, mActivityTestRule); 156 157 // Change the LiveData's value and verify that the observer's onChanged method is called 158 // since we are in the STARTED state. 159 mActivityTestRule.runOnUiThread(() -> mutableLiveData.setValue(1)); 160 assertThat(atomicInteger.get(), is(1)); 161 } 162 163 private FragmentActivity launchDialog() throws Throwable { 164 Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor( 165 NavigationDialogActivity.class.getCanonicalName(), null, false); 166 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 167 instrumentation.addMonitor(monitor); 168 169 FragmentActivity activity = mActivityTestRule.getActivity(); 170 // helps with less flaky API 16 tests 171 Intent intent = new Intent(activity, NavigationDialogActivity.class); 172 intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); 173 intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 174 activity.startActivity(intent); 175 FragmentActivity fragmentActivity = (FragmentActivity) monitor.waitForActivity(); 176 TestUtils.waitTillResumed(fragmentActivity, mActivityTestRule); 177 return fragmentActivity; 178 } 179 } 180