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 package android.system.helpers; 17 18 import android.app.Instrumentation; 19 import android.content.Context; 20 import android.provider.Settings; 21 import android.support.test.uiautomator.By; 22 import android.support.test.uiautomator.UiDevice; 23 import android.support.test.uiautomator.UiObject2; 24 import android.support.test.uiautomator.UiObjectNotFoundException; 25 import android.support.test.uiautomator.UiScrollable; 26 import android.support.test.uiautomator.UiSelector; 27 import android.support.test.uiautomator.Until; 28 29 /** 30 * Implement common helper functions for accessibility. 31 */ 32 public class AccessibilityHelper { 33 public static final String SETTINGS_PACKAGE = "com.android.settings"; 34 public static final String BUTTON = "android.widget.Button"; 35 public static final String CHECK_BOX = "android.widget.CheckBox"; 36 public static final String IMAGE_BUTTON = "android.widget.ImageButton"; 37 public static final String TEXT_VIEW = "android.widget.TextView"; 38 public static final String SWITCH = "android.widget.Switch"; 39 public static final String CHECKED_TEXT_VIEW = "android.widget.CheckedTextView"; 40 public static final String RADIO_BUTTON = "android.widget.RadioButton"; 41 public static final String SEEK_BAR = "android.widget.SeekBar"; 42 public static final String SPINNER = "android.widget.Spinner"; 43 public static final int SHORT_TIMEOUT = 2000; 44 public static final int LONG_TIMEOUT = 5000; 45 public static AccessibilityHelper sInstance = null; 46 private Context mContext = null; 47 private Instrumentation mInstrumentation = null; 48 private UiDevice mDevice = null; 49 private SettingsHelper mSettingsHelper = null; 50 51 public enum SwitchStatus { 52 ON, 53 OFF; 54 } 55 AccessibilityHelper(Instrumentation instr)56 private AccessibilityHelper(Instrumentation instr) { 57 mInstrumentation = instr; 58 mSettingsHelper = SettingsHelper.getInstance(); 59 mDevice = UiDevice.getInstance(instr); 60 mContext = mInstrumentation.getTargetContext(); 61 } 62 getInstance(Instrumentation instr)63 public static AccessibilityHelper getInstance(Instrumentation instr) { 64 if (sInstance == null) { 65 sInstance = new AccessibilityHelper(instr); 66 } 67 return sInstance; 68 } 69 70 /** 71 * Set Talkback "ON"/"OFF". 72 * 73 * @param value "ON"/"OFF" 74 * @throws Exception 75 */ setTalkBackSetting(SwitchStatus value)76 public void setTalkBackSetting(SwitchStatus value) throws Exception { 77 launchSpecificAccessibilitySetting("TalkBack"); 78 UiObject2 swtBar = mDevice.wait( 79 Until.findObject(By.res(SETTINGS_PACKAGE, "switch_bar")), SHORT_TIMEOUT) 80 .findObject(By.res(SETTINGS_PACKAGE, "switch_widget")); 81 if (swtBar != null && !swtBar.getText().equals(value.toString())) { 82 swtBar.click(); 83 UiObject2 confirmBtn = mDevice.wait( 84 Until.findObject(By.res("android:id/button1")), LONG_TIMEOUT); 85 if (confirmBtn != null) { 86 confirmBtn.click(); 87 } 88 // First time enable talkback, tutorial open. 89 if (mDevice.wait(Until.hasObject(By.text("TalkBack tutorial")), SHORT_TIMEOUT)) { 90 mDevice.pressBack(); // back to talkback setting page 91 } 92 } 93 mDevice.pressBack(); 94 } 95 96 /** 97 * Set high contrast "ON"/"OFF". 98 * 99 * @param value "ON"/"OFF" 100 * @throws Exception 101 */ setHighContrast(SwitchStatus value)102 public void setHighContrast(SwitchStatus value) throws Exception { 103 launchSpecificAccessibilitySetting("Accessibility"); 104 setSettingSwitchValue("High contrast text", value); 105 } 106 107 /** 108 * Launch specific accessibility setting page. 109 * 110 * @param settingName Specific accessibility setting name 111 * @throws Exception 112 */ launchSpecificAccessibilitySetting(String settingName)113 public void launchSpecificAccessibilitySetting(String settingName) throws Exception { 114 mSettingsHelper.launchSettingsPage(mContext, Settings.ACTION_ACCESSIBILITY_SETTINGS); 115 int maxTry = 3; 116 while (maxTry-- >= 0) { 117 Thread.sleep(SHORT_TIMEOUT); 118 UiObject2 actionBar = mDevice.wait(Until.findObject( 119 By.res(SETTINGS_PACKAGE, "action_bar").enabled(true)), SHORT_TIMEOUT); 120 if (actionBar == null) { 121 mSettingsHelper.launchSettingsPage(mContext, 122 Settings.ACTION_ACCESSIBILITY_SETTINGS); 123 } else { 124 String actionBarText = actionBar.findObject(By.clazz(TEXT_VIEW)).getText(); 125 if (actionBarText.equals(settingName)) { 126 break; 127 } else if (actionBarText.equals("Accessibility")) { 128 getSettingFromList(settingName).click(); 129 } else { 130 mDevice.wait(Until.findObject(By.res(SETTINGS_PACKAGE, "action_bar") 131 .enabled(true)), SHORT_TIMEOUT) 132 .findObject(By.clazz(IMAGE_BUTTON)).click(); 133 } 134 } 135 } 136 } 137 138 /** 139 * Set switch "ON"/"OFF". 140 * 141 * @param settingTag setting name 142 * @param value "ON"/"OFF" 143 * @return true/false 144 * @throws UiObjectNotFoundException 145 * @throws InterruptedException 146 */ setSettingSwitchValue(String settingTag, SwitchStatus value)147 private boolean setSettingSwitchValue(String settingTag, SwitchStatus value) 148 throws UiObjectNotFoundException, InterruptedException { 149 UiObject2 cellSwitch = getSettingFromList(settingTag) 150 .getParent().getParent().findObject(By.clazz(SWITCH)); 151 if (cellSwitch != null) { 152 if (!cellSwitch.getText().equals(value.toString())) { 153 cellSwitch.click(); 154 UiObject2 okBtn = mDevice.wait(Until.findObject( 155 By.res("android:id/button1")), LONG_TIMEOUT); 156 if (okBtn != null) { 157 okBtn.click(); 158 } 159 } 160 return cellSwitch.getText().equals(value.toString()); 161 } 162 return false; 163 } 164 165 /** 166 * Get setting name text object from list. 167 * 168 * @param settingName setting name 169 * @return UiObject2 170 * @throws UiObjectNotFoundException 171 */ getSettingFromList(String settingName)172 private UiObject2 getSettingFromList(String settingName) 173 throws UiObjectNotFoundException { 174 UiScrollable listScrollable = new UiScrollable( 175 new UiSelector().resourceId(SETTINGS_PACKAGE + ":id/recycler_view")); 176 if (listScrollable != null) { 177 listScrollable.scrollToBeginning(100); 178 listScrollable.scrollIntoView( 179 new UiSelector().resourceId("android:id/title").text(settingName)); 180 return mDevice.findObject(By.res("android:id/title").text(settingName)); 181 } else { 182 throw new UiObjectNotFoundException("Fail to get scrollable list %s."); 183 } 184 } 185 } 186