Home | History | Annotate | Download | only in cts
      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 android.preference2.cts;
     18 
     19 import static android.preference.PreferenceActivity.EXTRA_NO_HEADERS;
     20 import static android.preference.PreferenceActivity.EXTRA_SHOW_FRAGMENT;
     21 import static android.preference.PreferenceActivity.EXTRA_SHOW_FRAGMENT_TITLE;
     22 
     23 import static org.junit.Assert.assertEquals;
     24 import static org.junit.Assert.assertFalse;
     25 import static org.junit.Assert.assertTrue;
     26 
     27 import android.content.Intent;
     28 import android.graphics.Bitmap;
     29 import android.os.SystemClock;
     30 import android.preference2.cts.R;
     31 import android.util.Log;
     32 
     33 import com.android.compatibility.common.util.BitmapUtils;
     34 
     35 /**
     36  * This test suite covers {@link android.preference.PreferenceActivity} to ensure its correct
     37  * behavior in orientation and multi-window changes together with navigation between different
     38  * screens and going back in the history. It should also cover any possible transition between
     39  * single and multi pane modes. Some tests are designed to run only on large or small screen devices
     40  * and some can run both. These tests are run from {@link PreferenceActivityFlowLandscapeTest} and
     41  * {@link PreferenceActivityFlowPortraitTest} to ensure that both display configurations are
     42  * checked.
     43  */
     44 public abstract class PreferenceActivityFlowTest {
     45 
     46     private static final String TAG = "PreferenceFlowTest";
     47 
     48     // Helper strings to ensure that some parts of preferences are visible or not.
     49     private static final String PREFS1_HEADER_TITLE = "Prefs 1";
     50     private static final String PREFS2_HEADER_TITLE = "Prefs 2";
     51     private static final String PREFS1_PANEL_TITLE = "Preferences panel 1";
     52     private static final String PREFS2_PANEL_TITLE = "Preferences panel 2";
     53     private static final String INNER_FRAGMENT_PREF_BUTTON = "Fragment preference";
     54     private static final String INNER_FRAGMENT_PREF_TITLE = "Inner fragment";
     55     private static final String LIST_PREF_TITLE = "List preference";
     56     private static final String LIST_PREF_OPTION = "alpha";
     57 
     58     private static final int INITIAL_TITLE_RES_ID = R.string.test_title;
     59     private static final int EXPECTED_HEADERS_COUNT = 3;
     60 
     61     TestUtils mTestUtils;
     62     protected PreferenceWithHeaders mActivity;
     63     private boolean mIsMultiPane;
     64 
     65     void switchHeadersInner() {
     66         launchActivity();
     67         if (shouldRunLargeDeviceTest()) {
     68             largeScreenSwitchHeadersInner();
     69         } else {
     70             smallScreenSwitchHeadersInner();
     71         }
     72     }
     73 
     74     /**
     75      * For: Large screen (multi-pane).
     76      * Scenario: Tests that tapping on header changes to its proper preference panel and that the
     77      * headers are still visible.
     78      */
     79     private void largeScreenSwitchHeadersInner() {
     80         assertTrue(shouldRunLargeDeviceTest());
     81         assertInitialState();
     82 
     83         tapOnPrefs2Header();
     84 
     85         // Headers and panel Prefs2 must be shown.
     86         assertHeadersShown();
     87         assertPanelPrefs1Hidden();
     88         assertPanelPrefs2Shown();
     89 
     90         tapOnPrefs1Header();
     91 
     92         // Headers and panel Prefs1 must be shown.
     93         assertHeadersShown();
     94         assertPanelPrefs1Shown();
     95         assertPanelPrefs2Hidden();
     96     }
     97 
     98     /**
     99      * For: Small screen (single-pane).
    100      * Scenario: Tests that tapping on header changes to its proper preference panel and that the
    101      * headers are hidden and pressing back button after that shows them again.
    102      */
    103     private void smallScreenSwitchHeadersInner() {
    104         assertTrue(shouldRunSmallDeviceTest());
    105         assertInitialState();
    106 
    107         tapOnPrefs2Header();
    108 
    109         // Only Prefs2 must be shown.
    110         assertHeadersHidden();
    111         assertPanelPrefs1Hidden();
    112         assertPanelPrefs2Shown();
    113 
    114         pressBack();
    115 
    116         tapOnPrefs1Header();
    117 
    118         // Only Prefs1 must be shown.
    119         assertHeadersHidden();
    120         assertPanelPrefs1Shown();
    121         assertPanelPrefs2Hidden();
    122     }
    123 
    124     /**
    125      * For: Small screen (single-pane).
    126      * Scenario: Tests that after navigating back to the headers list there will be no header
    127      * highlighted and that the title was properly restored..
    128      */
    129     void smallScreenNoHighlightInHeadersListInner() {
    130         launchActivity();
    131         if (!shouldRunSmallDeviceTest()) {
    132             return;
    133         }
    134 
    135         assertInitialState();
    136 
    137         CharSequence title = mActivity.getTitle();
    138 
    139         tapOnPrefs2Header();
    140         assertHeadersHidden();
    141 
    142         pressBack();
    143         assertHeadersShown();
    144 
    145         // Verify that no headers are focused.
    146         assertHeadersNotFocused();
    147 
    148         // Verify that the title was properly restored.
    149         assertEquals(title, mActivity.getTitle());
    150 
    151         // Verify that everthing restores back to initial state again.
    152         assertInitialState();
    153     }
    154 
    155     void backPressToExitInner() {
    156         launchActivity();
    157         if (shouldRunLargeDeviceTest()) {
    158             largeScreenBackPressToExitInner();
    159         } else {
    160             smallScreenBackPressToExitInner();
    161         }
    162     }
    163 
    164     /**
    165      * For: Small screen (single-pane).
    166      * Scenario: Tests that pressing back button twice after having preference panel opened will
    167      * exit the app when running single-pane.
    168      */
    169     private void smallScreenBackPressToExitInner() {
    170         assertTrue(shouldRunSmallDeviceTest());
    171         assertInitialState();
    172 
    173         tapOnPrefs2Header();
    174 
    175         // Only Prefs2 must be shown - covered by smallScreenSwitchHeadersTest
    176 
    177         pressBack();
    178         pressBack();
    179 
    180         // Now we should be out of the activity
    181         assertHeadersHidden();
    182         assertPanelPrefs1Hidden();
    183         assertPanelPrefs2Hidden();
    184     }
    185 
    186     /**
    187      * For: Large screen (multi-pane).
    188      * Scenario: Selects a header and then leaves the activity by pressing back button. Tests that
    189      * we don't transition to the previous header or list of header like in single-pane.
    190      */
    191     private void largeScreenBackPressToExitInner() {
    192         assertTrue(shouldRunLargeDeviceTest());
    193         assertInitialState();
    194 
    195         tapOnPrefs2Header();
    196 
    197         // Headers and panel Prefs2 must be shown - covered by largeScreenSwitchHeadersInner.
    198 
    199         pressBack();
    200 
    201         assertHeadersHidden();
    202     }
    203 
    204     void goToFragmentInner() {
    205         launchActivity();
    206         if (shouldRunLargeDeviceTest()) {
    207             largeScreenGoToFragmentInner();
    208         } else {
    209             smallScreenGoToFragmentInner();
    210         }
    211     }
    212 
    213     /**
    214      * For: Large screen (multi-pane).
    215      * Scenario: Navigates to inner fragment. Test that the fragment was opened correctly and
    216      * headers are still visible. Also tests that back press doesn't close the app but navigates
    217      * back from the fragment.
    218      */
    219     private void largeScreenGoToFragmentInner() {
    220         assertTrue(shouldRunLargeDeviceTest());
    221         assertInitialState();
    222 
    223         tapOnPrefs1Header();
    224 
    225         // Go to preferences inner fragment.
    226         mTestUtils.tapOnViewWithText(INNER_FRAGMENT_PREF_BUTTON);
    227 
    228         // Headers and inner fragment must be shown.
    229         assertHeadersShown();
    230         assertPanelPrefs1Hidden();
    231         assertInnerFragmentShown();
    232 
    233         pressBack();
    234 
    235         // Headers and panel Prefs1 must be shown.
    236         assertHeadersShown();
    237         assertPanelPrefs1Shown();
    238         assertPanelPrefs2Hidden();
    239         assertInnerFragmentHidden();
    240     }
    241 
    242     /**
    243      * For: Small screen (single-pane).
    244      * Scenario: Navigates to inner fragment. Tests that the fragment was opened correctly and
    245      * headers are hidden. Also tests that back press doesn't close the app but navigates back from
    246      * the fragment.
    247      */
    248     private void smallScreenGoToFragmentInner() {
    249         assertTrue(shouldRunSmallDeviceTest());
    250         assertInitialState();
    251 
    252         tapOnPrefs1Header();
    253 
    254         // Go to preferences inner fragment.
    255         mTestUtils.tapOnViewWithText(INNER_FRAGMENT_PREF_BUTTON);
    256 
    257         // Only inner fragment must be shown.
    258         assertHeadersHidden();
    259         assertPanelPrefs1Hidden();
    260         assertInnerFragmentShown();
    261 
    262         pressBack();
    263 
    264         // Prefs1 must be shown.
    265         assertHeadersHidden();
    266         assertPanelPrefs1Shown();
    267         assertPanelPrefs2Hidden();
    268         assertInnerFragmentHidden();
    269     }
    270 
    271     /**
    272      * For: Any screen (single or multi-pane).
    273      * Scenario: Tests that opening specific preference fragment directly via intent works properly.
    274      */
    275     void startWithFragmentInner() {
    276         launchActivityWithExtras(PreferenceWithHeaders.PrefsTwoFragment.class,
    277                 false /* noHeaders */, -1 /* initialTitle */);
    278 
    279         assertInitialStateForFragment();
    280     }
    281 
    282     /**
    283      * For: Any screen (single or multi-pane).
    284      * Scenario: Tests that preference fragment opened directly survives recreation (via screenshot
    285      * tests).
    286      */
    287     void startWithFragmentAndRecreateInner() {
    288         launchActivityWithExtras(PreferenceWithHeaders.PrefsTwoFragment.class,
    289                 false /* noHeaders */, -1 /* initialTitle */);
    290 
    291         assertInitialStateForFragment();
    292 
    293         // Take screenshot
    294         Bitmap before = mTestUtils.takeScreenshot();
    295 
    296         // Force recreate
    297         recreate();
    298 
    299         assertInitialStateForFragment();
    300 
    301         // Compare screenshots
    302         Bitmap after = mTestUtils.takeScreenshot();
    303         assertScreenshotsAreEqual(before, after);
    304     }
    305 
    306     /**
    307      * For: Any screen (single or multi-pane).
    308      * Scenario: Starts preference fragment directly with the given initial title and tests that
    309      * multi-pane does not show it and single-pane does.
    310      */
    311     void startWithFragmentAndInitTitleInner() {
    312         launchActivityWithExtras(PreferenceWithHeaders.PrefsTwoFragment.class,
    313                 false /* noHeaders */, INITIAL_TITLE_RES_ID);
    314 
    315         assertInitialStateForFragment();
    316 
    317         if (mIsMultiPane) {
    318             String testTitle = mActivity.getResources().getString(INITIAL_TITLE_RES_ID);
    319             // Title should not be shown.
    320             assertTextHidden(testTitle);
    321         } else {
    322             // Title should be shown.
    323             assertTitleShown();
    324         }
    325     }
    326 
    327     /**
    328      * For: Large screen (multi-pane).
    329      * Scenario: Tests that initial title is displayed or hidden properly when transitioning in and
    330      * out of the multi-window mode.
    331      */
    332     void startWithFragmentAndInitTitleMultiWindowInner() {
    333         launchActivityWithExtras(PreferenceWithHeaders.PrefsTwoFragment.class,
    334                 false /* noHeaders */, INITIAL_TITLE_RES_ID);
    335         if (!shouldRunLargeDeviceTest()) {
    336             return;
    337         }
    338 
    339         assertInitialStateForFragment();
    340         String testTitle = mActivity.getResources().getString(INITIAL_TITLE_RES_ID);
    341 
    342         // Title should not be shown (we are in multi-pane).
    343         assertFalse(mTestUtils.isTextShown(testTitle));
    344 
    345         mTestUtils.enterMultiWindow(mActivity);
    346         mTestUtils.getMultiWindowFocus(mActivity);
    347 
    348         // Title should be shown (we are in single-pane).
    349         assertTextShown(testTitle);
    350 
    351         mTestUtils.leaveMultiWindow(mActivity);
    352 
    353         // Title should not be shown (we are back in multi-pane).
    354         assertTextHidden(testTitle);
    355     }
    356 
    357     /**
    358      * For: Any screen (single or multi-pane).
    359      * Scenario: Tests that EXTRA_NO_HEADERS intent arg that prevents showing headers in multi-pane
    360      * is applied correctly.
    361      */
    362     void startWithFragmentNoHeadersInner() {
    363         launchActivityWithExtras(PreferenceWithHeaders.PrefsTwoFragment.class,
    364                 true /* noHeaders */, -1 /* initialTitle */);
    365 
    366         assertInitialStateForFragment();
    367         // Only Prefs2 should be shown.
    368         assertHeadersHidden();
    369         assertPanelPrefs1Hidden();
    370         assertPanelPrefs2Shown();
    371     }
    372 
    373     /**
    374      * For: Any screen (single or multi-pane).
    375      * Scenario: Tests that EXTRA_NO_HEADERS intent arg that prevents showing headers in multi-pane
    376      * is applied correctly plus initial title is displayed.
    377      */
    378     void startWithFragmentNoHeadersButInitTitleInner() {
    379         launchActivityWithExtras(PreferenceWithHeaders.PrefsTwoFragment.class,
    380                 true /* noHeaders */, INITIAL_TITLE_RES_ID);
    381 
    382         assertInitialStateForFragment();
    383         // Only Prefs2 should be shown.
    384         assertHeadersHidden();
    385         assertPanelPrefs1Hidden();
    386         assertPanelPrefs2Shown();
    387 
    388         assertTitleShown();
    389     }
    390 
    391     /**
    392      * For: Any screen (single or multi-pane).
    393      * Scenario: Tests that EXTRA_NO_HEADERS intent arg that prevents showing headers survives
    394      * correctly multi-window changes. Tested via screenshots.
    395      */
    396     void startWithFragmentNoHeadersMultiWindowTest() {
    397         launchActivityWithExtras(PreferenceWithHeaders.PrefsTwoFragment.class,
    398                 true /* noHeaders */, -1 /* initialTitle */);
    399 
    400         assertInitialStateForFragment();
    401 
    402         // Workaround for some focus bug in the framework
    403         mTestUtils.tapOnViewWithText(PREFS2_PANEL_TITLE);
    404 
    405         // Take screenshot
    406         Bitmap before = mTestUtils.takeScreenshot();
    407 
    408         // Enter and leave multi-window.
    409         mTestUtils.enterMultiWindow(mActivity);
    410         mTestUtils.leaveMultiWindow(mActivity);
    411 
    412         assertInitialStateForFragment();
    413 
    414         // Compare screenshots
    415         Bitmap after = mTestUtils.takeScreenshot();
    416         assertScreenshotsAreEqual(before, after);
    417     }
    418 
    419     /**
    420      * For: Any screen (single or multi-pane).
    421      * Scenario: Tests that list preference opens correctly and that back press correctly closes it.
    422      */
    423     void listDialogTest()  {
    424         launchActivity();
    425 
    426         assertInitialState();
    427         if (!mIsMultiPane) {
    428             tapOnPrefs1Header();
    429         }
    430 
    431         mTestUtils.tapOnViewWithText(LIST_PREF_TITLE);
    432 
    433         mTestUtils.isTextShown(LIST_PREF_OPTION);
    434 
    435         pressBack();
    436 
    437         if (mIsMultiPane) {
    438             // Headers and Prefs1 should be shown.
    439             assertHeadersShown();
    440             assertPanelPrefs1Shown();
    441         } else {
    442             // Only Prefs1 should be shown.
    443             assertHeadersHidden();
    444             assertPanelPrefs1Shown();
    445         }
    446     }
    447 
    448     /**
    449      * For: Any screen (single or multi-pane).
    450      * Scenario: Tests that the PreferenceActivity properly restores its state after recreation.
    451      * Test done via screenshots.
    452      */
    453     void recreateTest() {
    454         launchActivity();
    455 
    456         assertInitialState();
    457         tapOnPrefs2Header();
    458 
    459         assertPanelPrefs2Shown();
    460 
    461         // Take screenshot
    462         Bitmap before = mTestUtils.takeScreenshot();
    463 
    464         recreate();
    465 
    466         assertPanelPrefs2Shown();
    467 
    468         // Compare screenshots
    469         Bitmap after = mTestUtils.takeScreenshot();
    470         assertScreenshotsAreEqual(before, after);
    471     }
    472 
    473     /**
    474      * For: Any screen (single or multi-pane).
    475      * Scenario: Tests that the PreferenceActivity properly restores its state after recreation
    476      * while an inner fragment is shown. Test done via screenshots.
    477      */
    478     void recreateInnerFragmentTest() {
    479         launchActivity();
    480 
    481         assertInitialState();
    482 
    483         if (!mIsMultiPane) {
    484             tapOnPrefs1Header();
    485         }
    486 
    487         // Go to preferences inner fragment.
    488         mTestUtils.tapOnViewWithText(INNER_FRAGMENT_PREF_BUTTON);
    489 
    490         // Only inner fragment must be shown.
    491         if (shouldRunLargeDeviceTest()) {
    492             assertHeadersShown();
    493         } else {
    494             assertHeadersHidden();
    495         }
    496         assertPanelPrefs1Hidden();
    497         assertInnerFragmentShown();
    498 
    499         // Take screenshot
    500         Bitmap before = mTestUtils.takeScreenshot();
    501 
    502         recreate();
    503 
    504         // Only inner fragment must be shown.
    505         if (shouldRunLargeDeviceTest()) {
    506             assertHeadersShown();
    507         } else {
    508             assertHeadersHidden();
    509         }
    510         assertPanelPrefs1Hidden();
    511         assertInnerFragmentShown();
    512 
    513         // Compare screenshots
    514         Bitmap after = mTestUtils.takeScreenshot();
    515         assertScreenshotsAreEqual(before, after);
    516     }
    517 
    518     /**
    519      * For: Any screen (single or multi-pane).
    520      * Scenario: Tests that the PreferenceActivity properly restores its state after going to
    521      * multi-window and back. Test done via screenshots.
    522      */
    523     void multiWindowInOutTest() {
    524         launchActivity();
    525 
    526         assertInitialState();
    527         // Tap on Prefs2 header.
    528         tapOnPrefs2Header();
    529 
    530         assertPanelPrefs2Shown();
    531 
    532         // Take screenshot
    533         Bitmap before = mTestUtils.takeScreenshot();
    534 
    535         // Enter and leave multi-window.
    536         mTestUtils.enterMultiWindow(mActivity);
    537         mTestUtils.leaveMultiWindow(mActivity);
    538 
    539         assertPanelPrefs2Shown();
    540 
    541         // Compare screenshots
    542         Bitmap after = mTestUtils.takeScreenshot();
    543         assertScreenshotsAreEqual(before, after);
    544     }
    545 
    546     /**
    547      * For: Any screen (single or multi-pane).
    548      * Scenario: Tests that the PreferenceActivity properly restores its state after going to
    549      * multi-window and back while an inner fragment is shown. Test done via screenshots.
    550      */
    551     void multiWindowInnerFragmentInOutTest() {
    552         launchActivity();
    553 
    554         assertInitialState();
    555         if (!mIsMultiPane) {
    556             tapOnPrefs1Header();
    557         }
    558 
    559         // Go to preferences inner fragment.
    560         mTestUtils.tapOnViewWithText(INNER_FRAGMENT_PREF_BUTTON);
    561 
    562         // We don't need to check that correct panel is displayed that is already covered by
    563         // smallScreenGoToFragmentInner and largeScreenGoToFragmentInner
    564 
    565         // Take screenshot
    566         Bitmap before = mTestUtils.takeScreenshot();
    567 
    568         // Enter and leave multi-window.
    569         mTestUtils.enterMultiWindow(mActivity);
    570         mTestUtils.leaveMultiWindow(mActivity);
    571 
    572         // Compare screenshots
    573         Bitmap after = mTestUtils.takeScreenshot();
    574         assertScreenshotsAreEqual(before, after);
    575     }
    576 
    577     /**
    578      * For: Large screen (single or multi-pane).
    579      * Scenario: Goes to single-pane by entering multi-window and tests that back press ends up with
    580      * a list of headers and nothing else. Then leaves multi-window back to single-pane and tests if
    581      * the proper default header was opened (screenshot test).
    582      */
    583     void multiWindowInitialHeaderOnBackTest() {
    584         launchActivity();
    585         if (!shouldRunLargeDeviceTest()) {
    586             return;
    587         }
    588 
    589         assertInitialState();
    590 
    591         Bitmap before = mTestUtils.takeScreenshot();
    592 
    593         // Enter multi-window.
    594         mTestUtils.enterMultiWindow(mActivity);
    595 
    596         // Get window focus (otherwise back press would close multi-window instead of firing to the
    597         // Activity.
    598         mTestUtils.getMultiWindowFocus(mActivity);
    599 
    600         pressBack();
    601 
    602         // Only headers should be shown (also checks that we have correct focus).
    603         assertHeadersShown();
    604         assertPanelPrefs1Hidden();
    605         assertPanelPrefs2Hidden();
    606 
    607         // Leave multi-window
    608         mTestUtils.leaveMultiWindow(mActivity);
    609 
    610         // Headers and Prefs1 should be shown.
    611         assertHeadersShown();
    612         assertPanelPrefs1Shown();
    613         assertPanelPrefs2Hidden();
    614 
    615         // Compare screenshots
    616         Bitmap after = mTestUtils.takeScreenshot();
    617         assertScreenshotsAreEqual(before, after);
    618     }
    619 
    620     /**
    621      * For: Large screen (multi-pane).
    622      * Scenario: Tests that history is preserved correctly while transitioning to multi-window.
    623      * Navigates to Prefs2 pane and then goes to single-pane mode via multi-window. Test that back
    624      * press navigates to the headers list. Then tests that restoring multi-pane by leaving
    625      * multi-window opens the same screen with which was the activity started before (screenshot
    626      * test).
    627      */
    628     void multiWindowHistoryPreserveTest() {
    629         launchActivity();
    630         if (!shouldRunLargeDeviceTest()) {
    631             return;
    632         }
    633 
    634         assertInitialState();
    635         Bitmap before = mTestUtils.takeScreenshot();
    636 
    637         tapOnPrefs2Header();
    638 
    639         // Enter multi-window.
    640         mTestUtils.enterMultiWindow(mActivity);
    641         mTestUtils.getMultiWindowFocus(mActivity);
    642 
    643         // Only Prefs2 should be shown (also checks that we have correct focus).
    644         assertHeadersHidden();
    645         assertPanelPrefs1Hidden();
    646         assertPanelPrefs2Shown();
    647 
    648         pressBack();
    649 
    650         // Only headers should be shown.
    651         assertHeadersShown();
    652         assertPanelPrefs1Hidden();
    653         assertPanelPrefs2Hidden();
    654 
    655         tapOnPrefs1Header();
    656 
    657         // Only Prefs1 should be shown.
    658         assertHeadersHidden();
    659         assertPanelPrefs1Shown();
    660         assertPanelPrefs2Hidden();
    661 
    662         // Leave multi-window
    663         mTestUtils.leaveMultiWindow(mActivity);
    664 
    665         // Headers and Prefs1 should be shown.
    666         assertHeadersShown();
    667         assertPanelPrefs1Shown();
    668         assertPanelPrefs2Hidden();
    669 
    670         // Compare screenshots
    671         Bitmap after = mTestUtils.takeScreenshot();
    672         assertScreenshotsAreEqual(before, after);
    673     }
    674 
    675     private void assertScreenshotsAreEqual(Bitmap before, Bitmap after) {
    676         assertTrue("Screenshots do not match!", BitmapUtils.compareBitmaps(before, after));
    677     }
    678 
    679     private void assertInitialState() {
    680         if (mIsMultiPane) {
    681             // Headers and panel Prefs1 must be shown.
    682             assertHeadersShown();
    683             runOnUiThread(() -> assertTrue(mActivity.hasHeaders()));
    684             assertPanelPrefs1Shown();
    685             assertPanelPrefs2Hidden();
    686         } else {
    687             // Headers must be shown and nothing else.
    688             assertHeadersShown();
    689             runOnUiThread(() -> assertTrue(mActivity.hasHeaders()));
    690             assertPanelPrefs1Hidden();
    691             assertPanelPrefs2Hidden();
    692         }
    693 
    694         assertHeadersAreLoaded();
    695     }
    696 
    697     private void assertInitialStateForFragment() {
    698         if (mIsMultiPane) {
    699             // Headers and Prefs2 should be shown.
    700             assertHeadersShown();
    701             runOnUiThread(() -> assertTrue(mActivity.hasHeaders()));
    702             assertPanelPrefs1Hidden();
    703             assertPanelPrefs2Shown();
    704         } else {
    705             // Only Prefs2 should be shown.
    706             assertHeadersHidden();
    707             runOnUiThread(() -> assertFalse(mActivity.hasHeaders()));
    708             assertPanelPrefs1Hidden();
    709             assertPanelPrefs2Shown();
    710         }
    711 
    712 
    713     }
    714 
    715     public boolean shouldRunLargeDeviceTest() {
    716         if (mActivity.onIsMultiPane()) {
    717             return true;
    718         }
    719 
    720         Log.d(TAG, "Skipping a large device test.");
    721         return false;
    722     }
    723 
    724     public boolean shouldRunSmallDeviceTest() {
    725         if (!mActivity.onIsMultiPane()) {
    726             return true;
    727         }
    728 
    729         Log.d(TAG, "Skipping a small device test.");
    730         return false;
    731     }
    732 
    733     private void tapOnPrefs1Header() {
    734         mTestUtils.tapOnViewWithText(PREFS1_HEADER_TITLE);
    735     }
    736 
    737     private void tapOnPrefs2Header() {
    738         mTestUtils.tapOnViewWithText(PREFS2_HEADER_TITLE);
    739     }
    740 
    741     private void assertHeadersAreLoaded() {
    742         runOnUiThread(() -> {
    743             assertEquals(EXPECTED_HEADERS_COUNT,
    744                     mActivity.loadedHeaders == null
    745                             ? 0
    746                             : mActivity.loadedHeaders.size());
    747         });
    748     }
    749 
    750     private void assertHeadersShown() {
    751         assertTextShown(PREFS1_HEADER_TITLE);
    752         assertTextShown(PREFS2_HEADER_TITLE);
    753     }
    754 
    755     private void assertHeadersNotFocused() {
    756         assertFalse(mTestUtils.isTextFocused(PREFS1_HEADER_TITLE));
    757         assertFalse(mTestUtils.isTextFocused(PREFS2_HEADER_TITLE));
    758     }
    759 
    760     private void assertHeadersHidden() {
    761         // We check '&' instead of each individual separately because these headers are also part
    762         // of individual preference panels breadcrumbs so it would fail for one.
    763         assertFalse(mTestUtils.isTextShown(PREFS1_HEADER_TITLE)
    764                 && mTestUtils.isTextShown(PREFS2_HEADER_TITLE));
    765     }
    766 
    767     private void assertPanelPrefs1Shown() {
    768         assertTextShown(PREFS1_PANEL_TITLE);
    769     }
    770 
    771     private void assertPanelPrefs1Hidden() {
    772         assertTextHidden(PREFS1_PANEL_TITLE);
    773     }
    774 
    775     private void assertPanelPrefs2Shown() {
    776         assertTextShown(PREFS2_PANEL_TITLE);
    777     }
    778 
    779     private void assertPanelPrefs2Hidden() {
    780         assertTextHidden(PREFS2_PANEL_TITLE);
    781     }
    782 
    783     private void assertInnerFragmentShown() {
    784         assertTextShown(INNER_FRAGMENT_PREF_TITLE);
    785     }
    786 
    787     private void assertInnerFragmentHidden() {
    788         assertTextHidden(INNER_FRAGMENT_PREF_TITLE);
    789     }
    790 
    791     private void assertTextShown(String text) {
    792         assertTrue(mTestUtils.isTextShown(text));
    793     }
    794 
    795     private void assertTextHidden(String text) {
    796         assertTrue(mTestUtils.isTextHidden(text));
    797     }
    798 
    799     private void assertTitleShown() {
    800         if (!mTestUtils.isOnWatchUiMode()) {
    801             // On watch, activity title is not shown by default.
    802             String testTitle = mActivity.getResources().getString(INITIAL_TITLE_RES_ID);
    803             assertTextShown(testTitle);
    804         }
    805     }
    806 
    807     private void recreate() {
    808         runOnUiThread(() -> mActivity.recreate());
    809         SystemClock.sleep(1000);
    810         waitForIdle();
    811     }
    812 
    813     private void waitForIdle() {
    814         mTestUtils.device.waitForIdle();
    815     }
    816 
    817     private void pressBack() {
    818         mTestUtils.device.pressBack();
    819         waitForIdle();
    820     }
    821 
    822     private void launchActivity() {
    823         mActivity = launchActivity(null);
    824         mTestUtils.device.waitForIdle();
    825         runOnUiThread(() -> {
    826             mIsMultiPane = mActivity.isMultiPane();
    827         });
    828     }
    829 
    830     private void launchActivityWithExtras(Class extraFragment, boolean noHeaders,
    831             int initialTitle) {
    832         Intent intent = new Intent(Intent.ACTION_MAIN);
    833 
    834         if (extraFragment != null) {
    835             intent.putExtra(EXTRA_SHOW_FRAGMENT, extraFragment.getName());
    836         }
    837         if (noHeaders) {
    838             intent.putExtra(EXTRA_NO_HEADERS, true);
    839         }
    840         if (initialTitle != -1) {
    841             intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE, initialTitle);
    842         }
    843 
    844         mActivity = launchActivity(intent);
    845         mTestUtils.device.waitForIdle();
    846         runOnUiThread(() -> {
    847             mIsMultiPane = mActivity.isMultiPane();
    848         });
    849     }
    850 
    851     protected abstract PreferenceWithHeaders launchActivity(Intent intent);
    852 
    853     protected abstract void runOnUiThread(final Runnable runnable);
    854 }
    855