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