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.downloadapp; 18 19 import android.app.AlarmManager; 20 import android.app.DownloadManager; 21 import android.app.DownloadManager.Query; 22 import android.app.DownloadManager.Request; 23 import android.content.ContentValues; 24 import android.content.Context; 25 import android.database.Cursor; 26 import android.icu.util.Calendar; 27 import android.net.Uri; 28 import android.os.Environment; 29 import android.support.test.launcherhelper.ILauncherStrategy; 30 import android.support.test.launcherhelper.LauncherStrategyFactory; 31 import android.support.test.uiautomator.By; 32 import android.support.test.uiautomator.UiDevice; 33 import android.support.test.uiautomator.UiObject2; 34 import android.support.test.uiautomator.Until; 35 import android.util.Log; 36 37 import junit.framework.Assert; 38 39 import java.util.ArrayList; 40 import java.util.Hashtable; 41 import java.util.List; 42 import java.util.Random; 43 44 public class DownloadAppTestHelper { 45 private static DownloadAppTestHelper mInstance = null; 46 public static final String[] FILE_TYPES = new String[] { 47 "pdf", "jpg", "jpeg", "doc", "xls", "txt", "rtf", "ppt", "gif", "png" 48 }; 49 50 public static final String PACKAGE_NAME = "com.android.documentsui"; 51 public static final String APP_NAME = "Downloads"; 52 public static final String TEST_TAG = "DownloadAppTest"; 53 public final int TIMEOUT = 500; 54 public final int MIN_FILENAME_LEN = 4; 55 private Context mContext = null; 56 private UiDevice mDevice = null; 57 private DownloadManager mDownloadMgr; 58 private Hashtable<String, DlObjSizeTimePair> mDownloadedItems = 59 new Hashtable<String, DlObjSizeTimePair>(); 60 public ILauncherStrategy mLauncherStrategy; 61 DownloadAppTestHelper(UiDevice device, Context context)62 private DownloadAppTestHelper(UiDevice device, Context context) { 63 mDevice = device; 64 mContext = context; 65 mLauncherStrategy = LauncherStrategyFactory.getInstance(mDevice).getLauncherStrategy(); 66 } 67 getInstance(UiDevice device, Context context)68 public static DownloadAppTestHelper getInstance(UiDevice device, Context context) { 69 if (mInstance == null) { 70 mInstance = new DownloadAppTestHelper(device, context); 71 } 72 return mInstance; 73 } 74 getDLManager()75 public DownloadManager getDLManager() { 76 return (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE); 77 } 78 launchApp(String packageName, String appName)79 public void launchApp(String packageName, String appName) { 80 if (!mDevice.hasObject(By.pkg(packageName).depth(0))) { 81 mLauncherStrategy.launch(appName, packageName); 82 } 83 } 84 85 /** sort items in Download app by name, size, time */ sortByParam(String sortby)86 public void sortByParam(String sortby) { 87 UiObject2 sortMenu = mDevice 88 .wait(Until.findObject(By.res(PACKAGE_NAME, "menu_sort")), 200); 89 if (sortMenu == null) { 90 mDevice.wait(Until.findObject(By.desc("More options")), 200).click(); 91 sortMenu = mDevice.wait(Until.findObject(By.res("android:id/submenuarrow")), 200); 92 } 93 sortMenu.click(); 94 mDevice.wait(Until.findObject(By.text(String.format("By %s", sortby))), 200).click(); 95 mDevice.waitForIdle(); 96 } 97 98 /** returns text list of items in Download app */ getDownloadItemNames()99 public List<String> getDownloadItemNames() { 100 List<UiObject2> itmesList = mDevice.wait(Until.findObjects(By.res("android:id/title")), 101 TIMEOUT); 102 List<String> nameList = new ArrayList<String>(); 103 for (UiObject2 item : itmesList) { 104 nameList.add(item.getText()); 105 } 106 return nameList; 107 } 108 109 /** verifies items in DownloadApp UI are sorted by name */ verifySortedByName()110 public Boolean verifySortedByName() { 111 List<String> nameList = getDownloadItemNames(); 112 for (int i = 0; i < (nameList.size() - 1); ++i) { 113 if (nameList.get(i).compareToIgnoreCase(nameList.get(i + 1)) > 0) { 114 return false; 115 } 116 } 117 return true; 118 } 119 120 /** verifies items in DownloadApp UI are sorted by size */ verifySortedBySize()121 public Boolean verifySortedBySize() { 122 List<String> nameList = getDownloadItemNames(); 123 for (int i = 0; i < (nameList.size() - 1); ++i) { 124 DlObjSizeTimePair firstItem = mDownloadedItems.get(nameList.get(i)); 125 DlObjSizeTimePair secondItem = mDownloadedItems.get(nameList.get(i + 1)); 126 if (firstItem != null && secondItem != null 127 && firstItem.dlObjSize < secondItem.dlObjSize) { 128 return false; 129 } 130 } 131 return true; 132 } 133 134 /** verifies items in DownloadApp UI are sorted by time */ verifySortedByTime()135 public Boolean verifySortedByTime() { 136 List<String> nameList = getDownloadItemNames(); 137 for (int i = 0; i < (nameList.size() - 1); ++i) { 138 DlObjSizeTimePair firstItem = mDownloadedItems.get(nameList.get(i)); 139 DlObjSizeTimePair secondItem = mDownloadedItems.get(nameList.get(i + 1)); 140 if (firstItem != null && secondItem != null 141 && firstItem.dlObjTimeInMilliSec < secondItem.dlObjTimeInMilliSec) { 142 return false; 143 } 144 } 145 return true; 146 } 147 verifyDownloadViewType(UIViewType view)148 public void verifyDownloadViewType(UIViewType view) { 149 int counter = 5; 150 UiObject2 viewTypeObj = null; 151 while ((viewTypeObj = mDevice.wait( 152 Until.findObject(By.res(String.format("%s:id/%s", 153 DownloadAppTestHelper.PACKAGE_NAME,view.toString()))),200)) == null 154 && counter-- > 0); 155 Assert.assertNotNull(viewTypeObj); 156 } 157 158 /** 159 * Create word of random assortment of lower/upper case letters 160 */ 161 /** set system time to random n[0..29] days earlier */ changeSystemTime(long timeToSet)162 public long changeSystemTime(long timeToSet) { 163 Calendar c = Calendar.getInstance(); 164 c.setTimeInMillis(timeToSet); 165 AlarmManager am = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 166 am.setTime(c.getTimeInMillis()); 167 return c.getTimeInMillis(); 168 } 169 170 /** add some content to download DB using DownloadManager.addCompletedDownload api */ populateContentInDLApp(int count)171 public void populateContentInDLApp(int count) { 172 int totalDownloaded = getTotalNumberDownloads(); 173 if (totalDownloaded >= count) { 174 return; 175 } 176 Random random = new Random(); 177 long currentTime = System.currentTimeMillis(); 178 for (int i = 0; i < (count - totalDownloaded); ++i) { 179 String fileName = String.format("%s.%s", 180 DownloadAppTestHelper.randomWord(random.nextInt(8) + MIN_FILENAME_LEN), 181 DownloadAppTestHelper.FILE_TYPES[random.nextInt(FILE_TYPES.length)]); 182 int size = random.nextInt(1000); 183 // changing system time to simulate the usecase "downloaded items over a period of time" 184 long timeInMiliSec = changeSystemTime( 185 System.currentTimeMillis() - random.nextInt(30 * 24) * (60 * 60 * 1000)); 186 long dlId = -1; 187 188 dlId = getDLManager().addCompletedDownload( 189 fileName, 190 String.format("%s Desc", 191 DownloadAppTestHelper.randomWord(random.nextInt(8) + MIN_FILENAME_LEN)), 192 Boolean.FALSE, 193 DownloadAppTestHelper.FILE_TYPES[random.nextInt(FILE_TYPES.length)], 194 Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) 195 .getAbsolutePath(), 196 size, Boolean.FALSE); 197 Assert.assertFalse("Add to DonwloadDB has failed!", dlId == -1); 198 Log.d(TEST_TAG, String.format("Adding Name = %s, size = %d, time = %d", fileName, 199 size, timeInMiliSec)); 200 mDownloadedItems.put(fileName, new DlObjSizeTimePair(size, timeInMiliSec)); 201 } 202 changeSystemTime(currentTime); 203 } 204 205 /** add some content to download DB directly in hacky way to bypass addCompletedDownload Api*/ addToDownloadContentDB(String title, String description, boolean isMediaScannerScannable, String mimeType, String path, long length, boolean showNotification)206 public long addToDownloadContentDB(String title, String description, 207 boolean isMediaScannerScannable, String mimeType, String path, long length, 208 boolean showNotification) { 209 210 boolean allowWrite = Boolean.FALSE; 211 Uri uri = Uri.parse("http://blah-blah"); // just put something in url format 212 Uri referer = null; 213 Request request; 214 request = new Request(uri); 215 ContentValues values = new ContentValues(); 216 /** 217 * a hacky way to insert into the Download DB direct bypassing the api with minimal data 218 * Constants have been taken from 219 * /platform/frameworks/base/+/master/core/java/android/provider/Downloads.java 220 */ 221 values.put("title", title); 222 values.put("description", description); 223 values.put("mimetype", mimeType); 224 values.put("is_public_api", true); 225 values.put("scanned", isMediaScannerScannable); 226 values.put("is_visible_in_downloads_ui", Boolean.TRUE); 227 values.put("destination", 6); // 6: show the download item in app 228 values.put("_data", path); // location to save the downloaded file 229 values.put("status", 200); // 200 : STATUS_SUCCESS 230 values.put("total_bytes", length); 231 values.put("visibility", (showNotification) 232 ? Request.VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION : Request.VISIBILITY_HIDDEN); 233 Uri downloadUri = mContext.getContentResolver() 234 .insert(Uri.parse("content://downloads/my_downloads"), values); 235 if (downloadUri == null) { 236 return -1; 237 } 238 return Long.parseLong(downloadUri.getLastPathSegment()); 239 } 240 241 /** remove downloads from download content db */ removeContentInDLApp()242 public void removeContentInDLApp() { 243 Cursor cursor = null; 244 try { 245 Query query = new Query(); 246 cursor = getDLManager().query(query); 247 int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_ID); 248 long[] removeIds = new long[cursor.getCount() - 1]; 249 Log.d(TEST_TAG, String.format("Remove Size is = %d", cursor.getCount())); 250 for (int i = 0; i < (cursor.getCount() - 1); i++) { 251 cursor.moveToNext(); 252 removeIds[i] = cursor.getLong(columnIndex); 253 } 254 if (removeIds.length > 0) { 255 Assert.assertEquals(removeIds.length, getDLManager().remove(removeIds)); 256 } 257 } finally { 258 if (cursor != null) { 259 cursor.close(); 260 } 261 } 262 } 263 getTotalNumberDownloads()264 public int getTotalNumberDownloads() { 265 Cursor cursor = null; 266 try { 267 Query query = new Query(); 268 cursor = getDLManager().query(query); 269 return cursor.getCount(); 270 } finally { 271 if (cursor != null) { 272 cursor.close(); 273 } 274 } 275 } 276 getDownloadItemCountById(long[] downloadId)277 public int getDownloadItemCountById(long[] downloadId) { 278 Cursor cursor = null; 279 int total = 0; 280 try { 281 Query query = new Query().setFilterById(downloadId); 282 cursor = getDLManager().query(query); 283 total = cursor.getCount(); 284 } finally { 285 if (cursor != null) { 286 cursor.close(); 287 } 288 } 289 290 return total; 291 } 292 randomWord(int length)293 public static String randomWord(int length) { 294 Random random = new Random(); 295 StringBuilder result = new StringBuilder(); 296 for (int j = 0; j < length; j++) { 297 int base = random.nextInt(2) == 0 ? 'A' : 'a'; 298 result.append((char) (random.nextInt(26) + base)); 299 } 300 return result.toString(); 301 } 302 303 /** 304 * Class to hold size and time info on downloaded items 305 */ 306 class DlObjSizeTimePair { 307 int dlObjSize; 308 long dlObjTimeInMilliSec; 309 DlObjSizeTimePair(int size, long time)310 public DlObjSizeTimePair(int size, long time) { 311 this.dlObjSize = size; 312 this.dlObjTimeInMilliSec = time; 313 } 314 } 315 316 public enum UIViewType { 317 LIST { toString()318 public String toString() { 319 return "menu_list"; 320 } 321 }, 322 GRID { toString()323 public String toString() { 324 return "menu_grid"; 325 } 326 } 327 }; 328 } 329