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 com.android.functional.externalstoragetests; 18 19 import android.app.Instrumentation; 20 import android.app.UiAutomation; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.pm.PackageInfo; 24 import android.content.pm.PackageManager; 25 import android.content.pm.PackageManager.NameNotFoundException; 26 import android.os.ParcelFileDescriptor; 27 import android.os.StatFs; 28 import android.os.SystemClock; 29 import android.provider.Settings; 30 import android.support.test.uiautomator.By; 31 import android.support.test.uiautomator.UiDevice; 32 import android.support.test.uiautomator.UiObject2; 33 import android.support.test.uiautomator.Until; 34 import android.util.Log; 35 36 import android.platform.test.helpers.PlayStoreHelperImpl; 37 38 import junit.framework.Assert; 39 40 import java.io.BufferedReader; 41 import java.io.File; 42 import java.io.FileInputStream; 43 import java.io.IOException; 44 import java.io.InputStreamReader; 45 import java.util.HashMap; 46 import java.util.Hashtable; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.regex.Matcher; 50 import java.util.regex.Pattern; 51 52 public class ExternalStorageHelper { 53 public static final String TEST_TAG = "StorageFunctionalTest"; 54 public final String SETTINGS_PKG = "com.android.settings"; 55 public final String PLAYSTORE_PKG = "com.android.vending"; 56 public final String DOCUMENTS_PKG = "com.android.documentsui"; 57 public static final Map<String, String> APPLIST = new HashMap<String, String>(); 58 static { 59 APPLIST.put("w35location1", "com.test.w35location1"); 60 APPLIST.put("w35location2", "com.test.w35location2"); 61 APPLIST.put("w35location3", "com.test.w35location3"); 62 } 63 public final int TIMEOUT = 2000; 64 public static ExternalStorageHelper mInstance = null; 65 public UiDevice mDevice; 66 public Context mContext; 67 public static UiAutomation mUiAutomation; 68 public static Instrumentation mInstrumentation; 69 public static Hashtable<String, List<String>> mPermissionGroupInfo = null; 70 ExternalStorageHelper(UiDevice device, Context context, UiAutomation uiAutomation, Instrumentation instrumentation)71 public ExternalStorageHelper(UiDevice device, Context context, UiAutomation uiAutomation, 72 Instrumentation instrumentation) { 73 mDevice = device; 74 mContext = context; 75 mUiAutomation = uiAutomation; 76 mInstrumentation = instrumentation; 77 } 78 getInstance(UiDevice device, Context context, UiAutomation uiAutomation, Instrumentation instrumentation)79 public static ExternalStorageHelper getInstance(UiDevice device, Context context, 80 UiAutomation uiAutomation, Instrumentation instrumentation) { 81 if (mInstance == null) { 82 mInstance = new ExternalStorageHelper(device, context, uiAutomation, instrumentation); 83 } 84 return mInstance; 85 } 86 87 /** 88 * Opens SD card setup notification from homescreen 89 */ openSdCardSetUpNotification()90 public UiObject2 openSdCardSetUpNotification() throws InterruptedException { 91 boolean success = mDevice.openNotification(); 92 Thread.sleep(TIMEOUT); 93 UiObject2 sdCardDetected = mDevice 94 .wait(Until.findObject(By.textContains("SD card detected")), TIMEOUT); 95 Assert.assertNotNull(sdCardDetected); 96 return sdCardDetected; 97 } 98 99 /** 100 * Open Storage settings, then SD Card 101 */ openStorageSettings()102 public void openStorageSettings() throws InterruptedException { 103 Intent intent = new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS); 104 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 105 mContext.startActivity(intent); 106 Thread.sleep(TIMEOUT * 2); 107 } 108 109 /** 110 * Open Storage settings, then SD Card 111 */ openSDCard()112 public void openSDCard() throws InterruptedException { 113 openStorageSettings(); 114 mDevice.wait(Until.findObject(By.textContains("SD card")), TIMEOUT) 115 .clickAndWait(Until.newWindow(), TIMEOUT); 116 } 117 executeShellCommand(String command)118 public String executeShellCommand(String command) { 119 ParcelFileDescriptor pfd = mUiAutomation.executeShellCommand(command); 120 try (BufferedReader reader = new BufferedReader( 121 new InputStreamReader(new FileInputStream(pfd.getFileDescriptor())))) { 122 String str = reader.readLine(); 123 Log.d(TEST_TAG, String.format("Executing command: %s", command)); 124 return str; 125 } catch (IOException e) { 126 Log.e(TEST_TAG, e.getMessage()); 127 } 128 129 return null; 130 } 131 132 /** 133 * Create # of files in a given dir 134 */ createFiles(int numberOfFiles, String dir)135 public void createFiles(int numberOfFiles, String dir) { 136 for (int i = 0; i < numberOfFiles; ++i) { 137 if (!new File(String.format("%s/Test_%d", dir, i)).exists()) { 138 fillInStorage(dir, String.format("Test_%d", i), 1); 139 } 140 } 141 } 142 fillInStorage(String location, String filename, int sizeInKb)143 public void fillInStorage(String location, String filename, int sizeInKb) { 144 executeShellCommand(String.format("dd if=/dev/zero of=%s/%s bs=1024 count=%d", 145 location, filename, sizeInKb)); 146 } 147 getFreeSpaceSize(File path)148 public int getFreeSpaceSize(File path) { 149 StatFs stat = new StatFs(path.getPath()); 150 long blockSize = stat.getBlockSize(); 151 long availableBlocks = stat.getAvailableBlocks(); 152 return (int) ((availableBlocks * blockSize) / (1024 * 1024)); 153 } 154 hasAdoptable()155 public boolean hasAdoptable() { 156 return Boolean.parseBoolean(executeShellCommand("sm has-adoptable").trim()); 157 } 158 getAdoptionDisk()159 public String getAdoptionDisk() throws InterruptedException { 160 int counter = 10; 161 String disks = null; 162 while (((disks == null || disks.length() == 0)) && counter > 0) { 163 disks = executeShellCommand("sm list-disks adoptable"); 164 Thread.sleep(TIMEOUT); 165 --counter; 166 } 167 if (counter == 0) { 168 throw new AssertionError("Devices must have adoptable media inserted"); 169 } 170 return disks.split("\n")[0].trim(); 171 } 172 hasPublicVolume()173 public Boolean hasPublicVolume() { 174 return (null != executeShellCommand("sm list-volumes public")); 175 } 176 getAdoptionVolumeId(String volType)177 public String getAdoptionVolumeId(String volType) throws InterruptedException { 178 return getAdoptionVolumeInfo(volType).volId; 179 } 180 getAdoptionVolumeUuid(String volType)181 public String getAdoptionVolumeUuid(String volType) throws InterruptedException { 182 return getAdoptionVolumeInfo(volType).uuid; 183 } 184 getAdoptionVolumeInfo(String volType)185 public LocalVolumeInfo getAdoptionVolumeInfo(String volType) throws InterruptedException { 186 String[] lines = null; 187 int attempt = 0; 188 while (attempt++ < 5) { 189 if (null != (lines = executeShellCommand("sm list-volumes " + volType).split("\n"))) { 190 for (String line : lines) { 191 final LocalVolumeInfo info = new LocalVolumeInfo(line.trim()); 192 if (info.volId.startsWith(volType) && "mounted".equals(info.state)) { 193 return info; 194 } 195 } 196 Thread.sleep(TIMEOUT); 197 } 198 } 199 return null; 200 } 201 partitionDisk(String type)202 public void partitionDisk(String type) throws InterruptedException { 203 if (type.equals("private")) { 204 executeShellCommand(String.format("sm partition %s %s", getAdoptionDisk(), type)); 205 Thread.sleep(2 * TIMEOUT); 206 } else if (!hasPublicVolume() && type.equals("public")) { 207 executeShellCommand("sm forget all"); 208 executeShellCommand(String.format("sm partition %s %s", getAdoptionDisk(), type)); 209 Thread.sleep(2 * TIMEOUT); 210 setupAsPortableUiFlow(); 211 } 212 } 213 setupAsPortableUiFlow()214 public void setupAsPortableUiFlow() throws InterruptedException { 215 openSdCardSetUpNotification(); 216 Thread.sleep(TIMEOUT); 217 Pattern pattern = Pattern.compile("Set up", Pattern.CASE_INSENSITIVE); 218 UiObject2 adoptFlowUi = mDevice.wait(Until.findObject(By.desc(pattern)), TIMEOUT); 219 adoptFlowUi.clickAndWait(Until.newWindow(), TIMEOUT); 220 adoptFlowUi = mDevice.wait(Until.findObject( 221 By.res(SETTINGS_PKG, "storage_wizard_init_external_title")), 222 TIMEOUT); 223 adoptFlowUi.click(); 224 pattern = Pattern.compile("Next", Pattern.CASE_INSENSITIVE); 225 adoptFlowUi = mDevice.wait(Until.findObject(By.text(pattern)), 226 TIMEOUT); 227 adoptFlowUi.clickAndWait(Until.newWindow(), TIMEOUT); 228 pattern = Pattern.compile("Done", Pattern.CASE_INSENSITIVE); 229 mDevice.wait(Until.findObject(By.text(pattern)), TIMEOUT).clickAndWait( 230 Until.newWindow(), TIMEOUT); 231 hasPublicVolume(); 232 233 } 234 installFromPlayStore(String appName)235 public void installFromPlayStore(String appName) { 236 PlayStoreHelperImpl mHelper = new PlayStoreHelperImpl(mInstrumentation); 237 mHelper.open(); 238 mHelper.doSearch(appName); 239 mHelper.selectFirstResult(); 240 mDevice.wait(Until.findObject(By.res(PLAYSTORE_PKG, "buy_button").text("INSTALL")), 241 TIMEOUT).clickAndWait(Until.newWindow(), 2 * TIMEOUT); 242 SystemClock.sleep(2 * TIMEOUT); 243 mDevice.wait(Until.findObject(By.res(PLAYSTORE_PKG, "launch_button").text("OPEN")), 244 5 * TIMEOUT); 245 } 246 getPackageInfo(String packageName)247 public PackageInfo getPackageInfo(String packageName) throws NameNotFoundException { 248 return mContext.getPackageManager().getPackageInfo(packageName, 0); 249 } 250 doesPackageExist(String packageName)251 public Boolean doesPackageExist(String packageName) throws NameNotFoundException { 252 try { 253 mContext.getPackageManager().getPackageInfo(packageName, 0); 254 } catch (NameNotFoundException nex) { 255 throw nex; 256 } 257 258 return Boolean.TRUE; 259 } 260 getInstalledLocation(String packageName)261 public String getInstalledLocation(String packageName) throws NameNotFoundException { 262 Assert.assertTrue(String.format("%s doesn't exist!", packageName), 263 doesPackageExist(packageName)); 264 return getPackageInfo(packageName).applicationInfo.dataDir; 265 } 266 settingsUiCleanUp()267 public void settingsUiCleanUp() { 268 executeShellCommand("pm clear " + SETTINGS_PKG); 269 executeShellCommand("pm clear " + DOCUMENTS_PKG); 270 } 271 272 private static class LocalVolumeInfo { 273 public String volId; 274 public String state; 275 public String uuid; 276 LocalVolumeInfo(String line)277 public LocalVolumeInfo(String line) { 278 final String[] split = line.split(" "); 279 volId = split[0]; 280 state = split[1]; 281 uuid = split[2]; 282 } 283 } 284 getPackageManager()285 public PackageManager getPackageManager() { 286 return mContext.getPackageManager(); 287 } 288 } 289