1 /* 2 * Copyright (C) 2016 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.system.helpers; 18 19 import static android.content.Context.CONTEXT_IGNORE_SECURITY; 20 21 import android.app.Instrumentation; 22 import android.content.Context; 23 import android.content.pm.PackageManager; 24 import android.content.res.Resources; 25 import android.graphics.Point; 26 import android.provider.Settings; 27 import android.text.TextUtils; 28 import android.util.Log; 29 30 import androidx.annotation.NonNull; 31 import androidx.test.uiautomator.By; 32 import androidx.test.uiautomator.BySelector; 33 import androidx.test.uiautomator.UiDevice; 34 import androidx.test.uiautomator.UiObject2; 35 import androidx.test.uiautomator.Until; 36 37 import org.junit.Assert; 38 39 import java.util.ArrayList; 40 import java.util.Arrays; 41 import java.util.List; 42 43 /** 44 * Implement common helper methods for Quick settings. 45 * 46 * @deprecated use classes from the "systemui-tapl" library instead 47 */ 48 @Deprecated 49 public class QuickSettingsHelper { 50 private static final String LOG_TAG = QuickSettingsHelper.class.getSimpleName(); 51 private static final int LONG_TIMEOUT = 2000; 52 private static final int SHORT_TIMEOUT = 500; 53 private static final String SYSTEMUI_PACKAGE = "com.android.systemui"; 54 private static final String QS_DEFAULT_TILES_RES = "quick_settings_tiles_default"; 55 private static final BySelector FOOTER_SELECTOR = By.res(SYSTEMUI_PACKAGE, "qs_footer"); 56 private static final String SYSUI_QS_TILES_SETTING = "sysui_qs_tiles"; 57 private static final String SET_QS_TILES_COMMAND = "cmd statusbar set-tiles "; 58 59 @NonNull private final UiDevice mDevice; 60 @NonNull private final Instrumentation mInstrumentation; 61 private List<String> mDefaultQSTileList = null; 62 private List<String> mPreviousQSTileList = null; 63 private final CommandsHelper mCommandsHelper; 64 QuickSettingsHelper(@onNull UiDevice device, @NonNull Instrumentation inst)65 public QuickSettingsHelper(@NonNull UiDevice device, @NonNull Instrumentation inst) { 66 this.mDevice = device; 67 mInstrumentation = inst; 68 mCommandsHelper = CommandsHelper.getInstance(mInstrumentation); 69 try { 70 obtainDefaultQSTiles(); 71 } catch (Exception e) { 72 Log.e(LOG_TAG, "obtainDefaultQSTiles fails!", e); 73 } 74 } 75 obtainDefaultQSTiles()76 private void obtainDefaultQSTiles() throws PackageManager.NameNotFoundException { 77 final Context sysUIContext = 78 mInstrumentation 79 .getContext() 80 .createPackageContext(SYSTEMUI_PACKAGE, CONTEXT_IGNORE_SECURITY); 81 final int qsTileListResId = 82 sysUIContext 83 .getResources() 84 .getIdentifier(QS_DEFAULT_TILES_RES, "string", SYSTEMUI_PACKAGE); 85 final String defaultQSTiles = sysUIContext.getString(qsTileListResId); 86 mDefaultQSTileList = Arrays.asList(defaultQSTiles.split(",")); 87 } 88 89 public enum QuickSettingDefaultTiles { 90 WIFI("Wi-Fi"), 91 SIM("Mobile data"), 92 DND("Do not disturb"), 93 FLASHLIGHT("Flashlight"), 94 SCREEN("Auto-rotate screen"), 95 BLUETOOTH("Bluetooth"), 96 AIRPLANE("Airplane mode"), 97 BRIGHTNESS("Display brightness"); 98 99 private final String name; 100 QuickSettingDefaultTiles(String name)101 QuickSettingDefaultTiles(String name) { 102 this.name = name; 103 } 104 getName()105 public String getName() { 106 return this.name; 107 } 108 } 109 110 public enum QuickSettingEditMenuTiles { 111 LOCATION("Location"), 112 HOTSPOT("Hotspot"), 113 INVERTCOLORS("Invert colors"), 114 DATASAVER("Data Saver"), 115 CAST("Cast"), 116 NEARBY("Nearby"); 117 118 private final String name; 119 QuickSettingEditMenuTiles(String name)120 QuickSettingEditMenuTiles(String name) { 121 this.name = name; 122 } 123 getName()124 public String getName() { 125 return this.name; 126 } 127 } 128 addQuickSettingTileFromEditMenu(String quickSettingTile, String quickSettingTileToReplace, String quickSettingTileToCheckForInCSV)129 public void addQuickSettingTileFromEditMenu(String quickSettingTile, 130 String quickSettingTileToReplace, String quickSettingTileToCheckForInCSV) 131 throws Exception { 132 // Draw down quick settings 133 launchQuickSetting(); 134 // Press Edit button 135 UiObject2 quickSettingEdit = mDevice.wait(Until.findObject 136 (By.descContains("Edit")), LONG_TIMEOUT); 137 quickSettingEdit.click(); 138 // Scroll down to bottom to see all QS options on Edit 139 swipeDown(); 140 // Drag and drop QS item onto existing QS tile to replace it 141 // This is because we need specific coordinates on which to 142 // drop the quick setting tile. 143 UiObject2 quickSettingTileObject = mDevice.wait(Until.findObject 144 (By.descContains(quickSettingTile)), LONG_TIMEOUT); 145 Point destination = mDevice.wait(Until.findObject 146 (By.descContains(quickSettingTileToReplace)), LONG_TIMEOUT) 147 .getVisibleCenter(); 148 Assert.assertNotNull(quickSettingTile + " in Edit menu can't be found", 149 quickSettingTileObject); 150 Assert.assertNotNull(quickSettingTileToReplace + " in QS menu can't be found", 151 destination); 152 // Long press the icon, then drag it to the destination slowly. 153 // Without the long press, it ends up scrolling down quick settings. 154 quickSettingTileObject.click(2000); 155 quickSettingTileObject.drag(destination, 1000); 156 // Hit the back button in the QS menu to go back to quick settings. 157 mDevice.wait(Until.findObject(By.descContains("Navigate up")), LONG_TIMEOUT); 158 // Retrieve the quick settings CSV string and verify that the newly 159 // added item is present. 160 String quickSettingsList = 161 Settings.Secure.getString( 162 mInstrumentation.getContext().getContentResolver(), SYSUI_QS_TILES_SETTING); 163 Assert.assertTrue( 164 quickSettingTile + " not present in qs tiles after addition.", 165 quickSettingsList.contains(quickSettingTileToCheckForInCSV)); 166 } 167 168 /** Sets default quick settings tile list pre-load in SystemUI resource. */ setQuickSettingsDefaultTiles()169 public void setQuickSettingsDefaultTiles() { 170 modifyQSTileList(mDefaultQSTileList); 171 } 172 173 /** Gets the default list of QuickSettings */ getQSDefaultTileList()174 public List<String> getQSDefaultTileList() { 175 return mDefaultQSTileList; 176 } 177 178 /** 179 * Set the tileName to be the first item for QS tiles. 180 * 181 * @param tileName tile name that will been set to the first position. 182 */ setFirstQS(@onNull String tileName)183 public void setFirstQS(@NonNull String tileName) { 184 mPreviousQSTileList = getCurrentTilesList(); 185 186 ArrayList<String> list = new ArrayList<>(mPreviousQSTileList); 187 for (int i = 0; i < list.size(); ++i) { 188 if (TextUtils.equals(tileName, list.get(i))) { 189 list.remove(i); 190 break; 191 } 192 } 193 list.add(0, tileName); 194 modifyQSTileList(list); 195 } 196 getCurrentTilesList()197 public List<String> getCurrentTilesList() { 198 String previousQSTiles = 199 Settings.Secure.getString( 200 mInstrumentation.getContext().getContentResolver(), SYSUI_QS_TILES_SETTING); 201 return Arrays.asList(previousQSTiles.split(",")); 202 } 203 204 /** Reset to previous QS tile list if exist */ resetToPreviousQSTileList()205 public void resetToPreviousQSTileList() { 206 if (mPreviousQSTileList == null) { 207 return; 208 } 209 modifyQSTileList(mPreviousQSTileList); 210 } 211 212 /** 213 * Sets customized tile list to secure settings entry 'sysui_qs_tiles' directly. 214 * 215 * @param list The quick settings tile list to be set 216 */ modifyQSTileList(@onNull List<String> list)217 public void modifyQSTileList(@NonNull List<String> list) { 218 if (list.isEmpty()) { 219 return; 220 } 221 222 try { 223 String settings = String.join(",", list); 224 mCommandsHelper.executeShellCommand(SET_QS_TILES_COMMAND + settings); 225 Thread.sleep(LONG_TIMEOUT); 226 } catch (Resources.NotFoundException | InterruptedException e) { 227 Log.e(LOG_TAG, "modifyQSTileList fails!", e); 228 } 229 } 230 231 /** Opens quick settings panel through {@link UiDevice#openQuickSettings()} */ launchQuickSetting()232 public void launchQuickSetting() { 233 mDevice.pressHome(); 234 mDevice.openQuickSettings(); 235 // Quick Settings isn't always open when this is complete. Explicitly wait for the Quick 236 // Settings footer to make sure that the buttons are accessible when the bar is open and 237 // this call is complete. 238 mDevice.wait(Until.findObject(FOOTER_SELECTOR), SHORT_TIMEOUT); 239 // Wait an extra bit for the animation to complete. If we return to early, future callers 240 // that are trying to find the location of the footer will get incorrect coordinates 241 mDevice.waitForIdle(LONG_TIMEOUT); 242 } 243 swipeUp()244 public void swipeUp() throws Exception { 245 mDevice.swipe(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight(), 246 mDevice.getDisplayWidth() / 2, 0, 30); 247 Thread.sleep(SHORT_TIMEOUT); 248 } 249 swipeDown()250 public void swipeDown() throws Exception { 251 mDevice.swipe( 252 mDevice.getDisplayWidth() / 2, 253 0, 254 mDevice.getDisplayWidth() / 2, 255 mDevice.getDisplayHeight(), 256 20); 257 Thread.sleep(SHORT_TIMEOUT); 258 } 259 swipeLeft()260 public void swipeLeft() { 261 mDevice.swipe(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight() / 2, 0, 262 mDevice.getDisplayHeight() / 2, 5); 263 } 264 } 265