Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 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 package android.fragment.cts;
     17 
     18 import static org.junit.Assert.assertEquals;
     19 import static org.junit.Assert.assertFalse;
     20 import static org.junit.Assert.assertNull;
     21 import static org.junit.Assert.assertTrue;
     22 
     23 import android.app.Fragment;
     24 import android.app.FragmentManager;
     25 import android.app.LoaderManager;
     26 import android.content.AsyncTaskLoader;
     27 import android.content.Context;
     28 import android.content.Loader;
     29 import android.os.Bundle;
     30 import android.os.SystemClock;
     31 import android.support.test.InstrumentationRegistry;
     32 import android.support.test.filters.MediumTest;
     33 import android.support.test.rule.ActivityTestRule;
     34 import android.support.test.runner.AndroidJUnit4;
     35 
     36 import org.junit.Rule;
     37 import org.junit.Test;
     38 import org.junit.runner.RunWith;
     39 
     40 import java.lang.ref.WeakReference;
     41 import java.util.concurrent.CountDownLatch;
     42 import java.util.concurrent.TimeUnit;
     43 
     44 @MediumTest
     45 @RunWith(AndroidJUnit4.class)
     46 public class LoaderTest {
     47     private static final int DELAY_LOADER = 10;
     48 
     49     @Rule
     50     public ActivityTestRule<LoaderActivity> mActivityRule =
     51             new ActivityTestRule<>(LoaderActivity.class);
     52 
     53     /**
     54      * Test to ensure that there is no Activity leak due to Loader
     55      */
     56     @Test
     57     public void testLeak() throws Throwable {
     58         // Restart the activity because mActivityRule keeps a strong reference to the
     59         // old activity.
     60         LoaderActivity activity = FragmentTestUtil.recreateActivity(mActivityRule,
     61                 mActivityRule.getActivity());
     62         LoaderFragment fragment = new LoaderFragment();
     63         FragmentManager fm = activity.getFragmentManager();
     64 
     65         fm.beginTransaction()
     66                 .add(fragment, "1")
     67                 .commit();
     68 
     69         FragmentTestUtil.executePendingTransactions(mActivityRule, fm);
     70 
     71         fm.beginTransaction()
     72                 .remove(fragment)
     73                 .addToBackStack(null)
     74                 .commit();
     75 
     76         FragmentTestUtil.executePendingTransactions(mActivityRule, fm);
     77         fm = null; // clear it so that it can be released
     78 
     79         WeakReference<LoaderActivity> weakActivity = new WeakReference(LoaderActivity.sActivity);
     80 
     81         activity = FragmentTestUtil.recreateActivity(mActivityRule, activity);
     82 
     83         // Wait for everything to settle. We have to make sure that the old Activity
     84         // is ready to be collected.
     85         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     86         FragmentTestUtil.waitForExecution(mActivityRule);
     87 
     88         // Now force a garbage collection.
     89         FragmentTestUtil.forceGC();
     90         assertNull(weakActivity.get());
     91     }
     92 
     93     /**
     94      * When a LoaderManager is reused, it should notify in onResume
     95      */
     96     @Test
     97     public void startWhenReused() throws Throwable {
     98         LoaderActivity activity = mActivityRule.getActivity();
     99         activity.waitForResume(mActivityRule);
    100         assertTrue(activity.loadFinished.await(1, TimeUnit.SECONDS));
    101 
    102         assertEquals("Loaded!", activity.textView.getText().toString());
    103 
    104         activity = FragmentTestUtil.recreateActivity(mActivityRule, activity);
    105         assertTrue(activity.loadFinished.await(1, TimeUnit.SECONDS));
    106 
    107         // After orientation change, the text should still be loaded properly
    108         assertEquals("Loaded!", activity.textView.getText().toString());
    109     }
    110 
    111     /**
    112      * When a change is interrupted with stop, the data in the LoaderManager remains stale.
    113      */
    114     @Test
    115     public void noStaleData() throws Throwable {
    116         final LoaderActivity activity = mActivityRule.getActivity();
    117         final String[] value = new String[] { "First Value" };
    118 
    119         final CountDownLatch[] loadedLatch = new CountDownLatch[] { new CountDownLatch(1) };
    120         final Loader<String>[] loaders = new Loader[1];
    121         mActivityRule.runOnUiThread(new Runnable() {
    122             @Override
    123             public void run() {
    124                 final Loader<String> loader =
    125                         activity.getLoaderManager().initLoader(DELAY_LOADER, null,
    126                                 new LoaderManager.LoaderCallbacks<String>() {
    127                                     @Override
    128                                     public Loader<String> onCreateLoader(int id, Bundle args) {
    129                                         return new AsyncTaskLoader<String>(activity) {
    130                                             @Override
    131                                             protected void onStopLoading() {
    132                                                 cancelLoad();
    133                                             }
    134 
    135                                             @Override
    136                                             public String loadInBackground() {
    137                                                 SystemClock.sleep(50);
    138                                                 return value[0];
    139                                             }
    140 
    141                                             @Override
    142                                             protected void onStartLoading() {
    143                                                 if (takeContentChanged()) {
    144                                                     forceLoad();
    145                                                 }
    146                                                 super.onStartLoading();
    147                                             }
    148                                         };
    149                                     }
    150 
    151                                     @Override
    152                                     public void onLoadFinished(Loader<String> loader, String data) {
    153                                         activity.textViewB.setText(data);
    154                                         loadedLatch[0].countDown();
    155                                     }
    156 
    157                                     @Override
    158                                     public void onLoaderReset(Loader<String> loader) {
    159                                     }
    160                                 });
    161                 loader.forceLoad();
    162                 loaders[0] = loader;
    163             }
    164         });
    165 
    166         assertTrue(loadedLatch[0].await(1, TimeUnit.SECONDS));
    167         assertEquals("First Value", activity.textViewB.getText().toString());
    168 
    169         loadedLatch[0] = new CountDownLatch(1);
    170         mActivityRule.runOnUiThread(new Runnable() {
    171             @Override
    172             public void run() {
    173                 value[0] = "Second Value";
    174                 loaders[0].onContentChanged();
    175                 loaders[0].stopLoading();
    176             }
    177         });
    178 
    179         // Since the loader was stopped (and canceled), it shouldn't notify the change
    180         assertFalse(loadedLatch[0].await(300, TimeUnit.MILLISECONDS));
    181 
    182         mActivityRule.runOnUiThread(new Runnable() {
    183             @Override
    184             public void run() {
    185                 loaders[0].startLoading();
    186             }
    187         });
    188 
    189         // Since the loader was stopped (and canceled), it shouldn't notify the change
    190         assertTrue(loadedLatch[0].await(1, TimeUnit.SECONDS));
    191         assertEquals("Second Value", activity.textViewB.getText().toString());
    192     }
    193 
    194     public static class LoaderFragment extends Fragment {
    195         private static final int LOADER_ID = 1;
    196         private final LoaderManager.LoaderCallbacks<Boolean> mLoaderCallbacks =
    197                 new LoaderManager.LoaderCallbacks<Boolean>() {
    198                     @Override
    199                     public Loader<Boolean> onCreateLoader(int id, Bundle args) {
    200                         return new DummyLoader(getContext());
    201                     }
    202 
    203                     @Override
    204                     public void onLoadFinished(Loader<Boolean> loader, Boolean data) {
    205 
    206                     }
    207 
    208                     @Override
    209                     public void onLoaderReset(Loader<Boolean> loader) {
    210 
    211                     }
    212                 };
    213 
    214         @Override
    215         public void onActivityCreated(Bundle savedInstanceState) {
    216             super.onActivityCreated(savedInstanceState);
    217 
    218             getLoaderManager().initLoader(LOADER_ID, null, mLoaderCallbacks);
    219         }
    220     }
    221 
    222     static class DummyLoader extends Loader<Boolean> {
    223         DummyLoader(Context context) {
    224             super(context);
    225         }
    226 
    227         @Override
    228         protected void onStartLoading() {
    229             deliverResult(true);
    230         }
    231     }
    232 }
    233