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 62 private DownloadAppTestHelper(UiDevice device, Context context) { 63 mDevice = device; 64 mContext = context; 65 mLauncherStrategy = LauncherStrategyFactory.getInstance(mDevice).getLauncherStrategy(); 66 } 67 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 75 public DownloadManager getDLManager() { 76 return (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE); 77 } 78 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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*/ 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 */ 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 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 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 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 310 public DlObjSizeTimePair(int size, long time) { 311 this.dlObjSize = size; 312 this.dlObjTimeInMilliSec = time; 313 } 314 } 315 316 public enum UIViewType { 317 LIST { 318 public String toString() { 319 return "menu_list"; 320 } 321 }, 322 GRID { 323 public String toString() { 324 return "menu_grid"; 325 } 326 } 327 }; 328 } 329