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 17 package com.android.documentsui; 18 19 import static com.android.documentsui.StubProvider.ROOT_0_ID; 20 import static com.android.documentsui.StubProvider.ROOT_1_ID; 21 22 import android.content.Context; 23 import android.content.ContentResolver; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.BroadcastReceiver; 27 import android.net.Uri; 28 import android.os.Bundle; 29 import android.os.RemoteException; 30 import android.provider.Settings; 31 import android.support.test.filters.LargeTest; 32 import android.support.test.filters.Suppress; 33 import android.support.test.uiautomator.Configurator; 34 import android.text.TextUtils; 35 import android.view.KeyEvent; 36 import android.view.MotionEvent; 37 38 import com.android.documentsui.base.DocumentInfo; 39 import com.android.documentsui.files.FilesActivity; 40 import com.android.documentsui.services.TestNotificationService; 41 42 import java.util.concurrent.ArrayBlockingQueue; 43 import java.util.concurrent.CountDownLatch; 44 import java.util.concurrent.RejectedExecutionException; 45 import java.util.concurrent.ThreadPoolExecutor; 46 import java.util.concurrent.TimeUnit; 47 import java.util.List; 48 import java.util.ArrayList; 49 50 /** 51 * This class test the below points 52 * - Copy large number of files 53 */ 54 @LargeTest 55 public class FileCopyUiTest extends ActivityTest<FilesActivity> { 56 private static final String PACKAGE_NAME = "com.android.documentsui.tests"; 57 58 private static final String ACCESS_APP_NAME = "DocumentsUI Tests"; 59 60 private static final String ALLOW = "ALLOW"; 61 62 private static final String TURN_OFF = "TURN OFF"; 63 64 private static final String COPY = "Copy to"; 65 66 private static final String MOVE = "Move to"; 67 68 private static final String SELECT_ALL = "Select all"; 69 70 private static final int DUMMY_FILE_COUNT = 1000; 71 72 private final List<String> mCopyFileList = new ArrayList<String>(); 73 74 private final BroadcastReceiver mReceiver = new BroadcastReceiver() { 75 @Override 76 public void onReceive(Context context, Intent intent) { 77 String action = intent.getAction(); 78 if (TestNotificationService.ACTION_OPERATION_RESULT.equals(action)) { 79 mOperationExecuted = intent.getBooleanExtra( 80 TestNotificationService.EXTRA_RESULT, false); 81 if (!mOperationExecuted) { 82 mErrorReason = intent.getStringExtra( 83 TestNotificationService.EXTRA_ERROR_REASON); 84 } 85 mCountDownLatch.countDown(); 86 } 87 } 88 }; 89 90 private CountDownLatch mCountDownLatch; 91 92 private boolean mOperationExecuted; 93 94 private String mErrorReason; 95 96 public FileCopyUiTest() { 97 super(FilesActivity.class); 98 } 99 100 @Override 101 public void setUp() throws Exception { 102 super.setUp(); 103 104 // Set a flag to prevent many refreshes. 105 Bundle bundle = new Bundle(); 106 bundle.putBoolean(StubProvider.EXTRA_ENABLE_ROOT_NOTIFICATION, false); 107 mDocsHelper.configure(null, bundle); 108 109 initTestFiles(); 110 111 IntentFilter filter = new IntentFilter(); 112 filter.addAction(TestNotificationService.ACTION_OPERATION_RESULT); 113 context.registerReceiver(mReceiver, filter); 114 context.sendBroadcast(new Intent( 115 TestNotificationService.ACTION_CHANGE_EXECUTION_MODE)); 116 117 mOperationExecuted = false; 118 mErrorReason = "No response from Notification"; 119 mCountDownLatch = new CountDownLatch(1); 120 } 121 122 @Override 123 public void tearDown() throws Exception { 124 mCountDownLatch.countDown(); 125 mCountDownLatch = null; 126 127 context.unregisterReceiver(mReceiver); 128 try { 129 if (isEnableAccessNotification()) { 130 disallowNotificationAccess(); 131 } 132 } catch (Exception e) { 133 // ignore 134 } 135 super.tearDown(); 136 } 137 138 @Override 139 public void initTestFiles() throws RemoteException { 140 try { 141 if (!isEnableAccessNotification()) { 142 allowNotificationAccess(); 143 } 144 createDummyFiles(); 145 } catch (Exception e) { 146 fail("Initialization failed"); 147 } 148 } 149 150 private void createDummyFiles() throws Exception { 151 final ThreadPoolExecutor exec = new ThreadPoolExecutor( 152 5, 5, 1000L, TimeUnit.MILLISECONDS, 153 new ArrayBlockingQueue<Runnable>(100, true)); 154 for (int i = 0; i < DUMMY_FILE_COUNT; i++) { 155 final String fileName = "file" + String.format("%04d", i) + ".log"; 156 if (exec.getQueue().size() >= 80) { 157 Thread.sleep(50); 158 } 159 exec.submit(new Runnable() { 160 @Override 161 public void run() { 162 Uri uri = mDocsHelper.createDocument(rootDir0, "text/plain", fileName); 163 try { 164 mDocsHelper.writeDocument(uri, new byte[1]); 165 } catch (Exception e) { 166 // ignore 167 } 168 } 169 }); 170 mCopyFileList.add(fileName); 171 } 172 exec.shutdown(); 173 } 174 175 private void allowNotificationAccess() throws Exception { 176 Intent intent = new Intent(); 177 intent.setAction(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS); 178 getActivity().startActivity(intent); 179 device.waitForIdle(); 180 181 bots.main.findMenuLabelWithName(ACCESS_APP_NAME).click(); 182 device.waitForIdle(); 183 184 bots.main.findMenuLabelWithName(ALLOW).click(); 185 bots.keyboard.pressKey(KeyEvent.KEYCODE_BACK); 186 } 187 188 private void disallowNotificationAccess() throws Exception { 189 Intent intent = new Intent(); 190 intent.setAction(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS); 191 getActivity().startActivity(intent); 192 device.waitForIdle(); 193 194 bots.main.findMenuLabelWithName(ACCESS_APP_NAME).click(); 195 device.waitForIdle(); 196 197 bots.main.findMenuLabelWithName(TURN_OFF).click(); 198 bots.keyboard.pressKey(KeyEvent.KEYCODE_BACK); 199 } 200 201 private boolean isEnableAccessNotification() { 202 ContentResolver resolver = getActivity().getContentResolver(); 203 String listeners = Settings.Secure.getString( 204 resolver,"enabled_notification_listeners"); 205 if (!TextUtils.isEmpty(listeners)) { 206 String[] list = listeners.split(":"); 207 for(String item : list) { 208 if(item.startsWith(PACKAGE_NAME)) { 209 return true; 210 } 211 } 212 } 213 return false; 214 } 215 216 public void testCopyAllDocument() throws Exception { 217 bots.roots.openRoot(ROOT_0_ID); 218 bots.main.clickToolbarOverflowItem(SELECT_ALL); 219 device.waitForIdle(); 220 221 bots.main.clickToolbarOverflowItem(COPY); 222 device.waitForIdle(); 223 224 bots.roots.openRoot(ROOT_1_ID); 225 bots.main.clickDialogOkButton(); 226 device.waitForIdle(); 227 228 try { 229 mCountDownLatch.await(60, TimeUnit.SECONDS); 230 } catch (Exception e) { 231 fail("Cannot wait because of error." + e.toString()); 232 } 233 234 assertTrue(mErrorReason, mOperationExecuted); 235 236 bots.roots.openRoot(ROOT_1_ID); 237 device.waitForIdle(); 238 239 List<DocumentInfo> root1 = mDocsHelper.listChildren(rootDir1.documentId, 1000); 240 List<String> copiedFileList = new ArrayList<String>(); 241 for (DocumentInfo info : root1) { 242 copiedFileList.add(info.displayName); 243 } 244 245 for (String name : mCopyFileList) { 246 assertTrue("Not found " + name, copiedFileList.contains(name)); 247 } 248 } 249 } 250