1 /* 2 * Copyright (C) 2018 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 com.android.settings.ui; 18 19 import static com.android.settings.ui.testutils.SettingsTestUtils.SETTINGS_PACKAGE; 20 import static com.google.common.truth.Truth.assertThat; 21 import static com.google.common.truth.Truth.assertWithMessage; 22 23 import android.app.Instrumentation; 24 import android.content.Intent; 25 import android.os.RemoteException; 26 import android.provider.Settings; 27 import android.support.test.uiautomator.By; 28 import android.support.test.uiautomator.Direction; 29 import android.support.test.uiautomator.UiDevice; 30 import android.support.test.uiautomator.UiObject2; 31 import android.support.test.uiautomator.Until; 32 import android.text.TextUtils; 33 34 import androidx.test.InstrumentationRegistry; 35 import androidx.test.filters.SmallTest; 36 import androidx.test.runner.AndroidJUnit4; 37 38 import org.junit.After; 39 import org.junit.Before; 40 import org.junit.Test; 41 import org.junit.runner.RunWith; 42 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.Iterator; 46 47 /** Verifies basic functionality of the About Phone screen */ 48 @RunWith(AndroidJUnit4.class) 49 @SmallTest 50 public class AboutPhoneSettingsTests { 51 private static final int TIMEOUT = 2000; 52 53 // TODO: retrieve using name/ids from com.android.settings package 54 private static final String[] sResourceTexts = { 55 "Phone number", 56 "Legal information", 57 "Regulatory labels" 58 }; 59 60 private UiDevice mDevice; 61 private Instrumentation mInstrumentation; 62 63 @Before setUp()64 public void setUp() throws Exception { 65 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 66 mDevice = UiDevice.getInstance(mInstrumentation); 67 try { 68 mDevice.setOrientationNatural(); 69 } catch (RemoteException e) { 70 throw new RuntimeException("Failed to freeze device orientaion", e); 71 } 72 73 // make sure we are in a clean state before starting the test 74 mDevice.pressHome(); 75 Thread.sleep(TIMEOUT * 2); 76 launchAboutPhoneSettings(Settings.ACTION_DEVICE_INFO_SETTINGS); 77 // TODO: make sure we are always at the top of the app 78 // currently this will fail if the user has navigated into submenus 79 UiObject2 view = 80 mDevice.wait( 81 Until.findObject(By.res(SETTINGS_PACKAGE + ":id/main_content")), TIMEOUT); 82 assertThat(view).isNotNull(); 83 view.scroll(Direction.UP, 1.0f); 84 } 85 86 @After tearDown()87 public void tearDown() throws Exception { 88 // Adding an extra pressBack so we exit About Phone Settings 89 // and finish the test cleanly 90 mDevice.pressBack(); 91 mDevice.pressHome(); // finish settings activity 92 mDevice.waitForIdle(TIMEOUT * 2); // give UI time to finish animating 93 } 94 95 @Test testAllMenuEntriesExist()96 public void testAllMenuEntriesExist() { 97 searchForItemsAndTakeAction(mDevice, sResourceTexts); 98 } 99 launchAboutPhoneSettings(String aboutSetting)100 private void launchAboutPhoneSettings(String aboutSetting) { 101 Intent aboutIntent = new Intent(aboutSetting); 102 aboutIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 103 InstrumentationRegistry.getTargetContext().startActivity(aboutIntent); 104 } 105 106 /** 107 * Removes items found in the view and optionally takes some action. 108 */ removeItemsAndTakeAction(UiDevice device, ArrayList<String> itemsLeftToFind)109 private void removeItemsAndTakeAction(UiDevice device, ArrayList<String> itemsLeftToFind) { 110 for (Iterator<String> iterator = itemsLeftToFind.iterator(); iterator.hasNext(); ) { 111 String itemText = iterator.next(); 112 UiObject2 item = device.wait(Until.findObject(By.text(itemText)), TIMEOUT); 113 if (item != null) { 114 iterator.remove(); 115 } 116 } 117 } 118 119 /** 120 * Searches for UI elements in the current view and optionally takes some action. 121 * 122 * <p>Will scroll down the screen until it has found all elements or reached the bottom. 123 * This allows elements to be found and acted on even if they change order. 124 */ searchForItemsAndTakeAction(UiDevice device, String[] itemsToFind)125 private void searchForItemsAndTakeAction(UiDevice device, String[] itemsToFind) { 126 127 ArrayList<String> itemsLeftToFind = new ArrayList<>(Arrays.asList(itemsToFind)); 128 assertWithMessage("There must be at least one item to search for on the screen!") 129 .that(itemsLeftToFind) 130 .isNotEmpty(); 131 132 boolean canScrollDown = true; 133 while (canScrollDown && !itemsLeftToFind.isEmpty()) { 134 removeItemsAndTakeAction(device, itemsLeftToFind); 135 136 // when we've finished searching the current view, scroll down 137 UiObject2 view = 138 device.wait( 139 Until.findObject(By.res(SETTINGS_PACKAGE + ":id/main_content")), 140 TIMEOUT * 2); 141 if (view != null) { 142 canScrollDown = view.scroll(Direction.DOWN, 1.0f); 143 } else { 144 canScrollDown = false; 145 } 146 } 147 // check the last items once we have reached the bottom of the view 148 removeItemsAndTakeAction(device, itemsLeftToFind); 149 150 assertWithMessage("The following items were not found on the screen: " 151 + TextUtils.join(", ", itemsLeftToFind)) 152 .that(itemsLeftToFind) 153 .isEmpty(); 154 } 155 } 156