Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3bdd3f56 authored by Takamasa Kuramitsu's avatar Takamasa Kuramitsu
Browse files

Refactor some file operation UI tests

Reduce dependencies to the external factors from some file operation
tests.
- Avoid depending on system notification for virtual SD setup
- Remove hard-corded string

Bug: 109708230
Test: Run instrumentation tests from com.android.documentsui.tests
Change-Id: I076c8df572d78087287263834b51d0ef5a553b67
parent ff23d0bc
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;
@@ -40,12 +41,21 @@ public class NotificationsBot extends Bots.BaseBot {
        super(device, context, timeout);
    }

    public void setNotificationAccess(Activity activity, String appName, boolean enabled)
    public void setNotificationAccess(Activity activity, boolean enabled)
            throws UiObjectNotFoundException, NameNotFoundException {
        Context testContext = InstrumentationRegistry.getContext();

        if(isNotificationAccessEnabled(
                mContext.getContentResolver(), testContext.getPackageName()) == enabled) {
            return;
        }

        Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
        activity.startActivity(intent);
        mDevice.waitForIdle();

        String appName = testContext.getPackageManager().getApplicationLabel(
                testContext.getApplicationInfo()).toString();
        clickLabel(appName);

        Context settings_context = mContext.createPackageContext(SETTINGS_PACKAGE_NAME,
@@ -59,7 +69,7 @@ public class NotificationsBot extends Bots.BaseBot {
        mDevice.waitForIdle();
    }

    public boolean isNotificationAccessEnabled(ContentResolver resolver, String pkgName) {
    private boolean isNotificationAccessEnabled(ContentResolver resolver, String pkgName) {
        String listeners = Settings.Secure.getString(resolver, "enabled_notification_listeners");
        if (!TextUtils.isEmpty(listeners)) {
            String[] list = listeners.split(":");
+1 −27
Original line number Diff line number Diff line
@@ -48,12 +48,6 @@ public class TestNotificationService extends NotificationListenerService {
    public static final String ACTION_OPERATION_RESULT =
            "com.android.documentsui.services.TestNotificationService.ACTION_OPERATION_RESULT";

    public static final String ACTION_DISPLAY_SD_CARD_NOTIFICATION =
            "com.android.documentsui.services.TestNotificationService.ACTION_DISPLAY_SD_CARD_NOTIFICATION";

    public static final String ACTION_SD_CARD_SETTING_COMPLETED =
            "com.android.documentsui.services.TestNotificationService.ACTION_SD_CARD_SETTING_COMPLETED";

    public static final String ANDROID_PACKAGENAME = "android";

    public static final String CANCEL_RES_NAME = "cancel";
@@ -64,16 +58,8 @@ public class TestNotificationService extends NotificationListenerService {
    public static final String EXTRA_ERROR_REASON =
            "com.android.documentsui.services.TestNotificationService.EXTRA_ERROR_REASON";

    public static final String UNSUPPORTED_NOTIFICATION_TEXT = "Issue with Virtual SD card";

    public static final String CORRUPTED_NOTIFICATION_TEXT = "Corrupted Virtual SD card";

    public static final String VIRTUAL_SD_CARD_TEXT = "Virtual SD card";

    private final static String DOCUMENTSUI_PACKAGE= "com.android.documentsui";

    private final static String SD_CARD_NOTIFICATION_PACKAGE = "com.android.systemui";

    public enum MODE {
        CANCEL_MODE,
        EXECUTION_MODE;
@@ -124,9 +110,7 @@ public class TestNotificationService extends NotificationListenerService {
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        String pkgName = sbn.getPackageName();
        if (SD_CARD_NOTIFICATION_PACKAGE.equals(pkgName)) {
            sendBroadcastForVirtualSdCard(sbn.getNotification());
        } else if (DOCUMENTSUI_PACKAGE.equals(pkgName)) {
        if (DOCUMENTSUI_PACKAGE.equals(pkgName)) {
            if (MODE.CANCEL_MODE.equals(mCurrentMode)) {
                try {
                    mCancelled = doCancel(sbn.getNotification());
@@ -160,16 +144,6 @@ public class TestNotificationService extends NotificationListenerService {
        sendBroadcast(intent);
    }

    private void sendBroadcastForVirtualSdCard(Notification notification) {
        String title = notification.extras.getString(Notification.EXTRA_TITLE);
        if (UNSUPPORTED_NOTIFICATION_TEXT.equals(title) ||
                CORRUPTED_NOTIFICATION_TEXT.equals(title)) {
            sendBroadcast(new Intent(ACTION_DISPLAY_SD_CARD_NOTIFICATION));
        } else if (VIRTUAL_SD_CARD_TEXT.equals(title)) {
            sendBroadcast(new Intent(ACTION_SD_CARD_SETTING_COMPLETED));
        }
    }

    private boolean doCancel(Notification noti)
            throws NameNotFoundException, PendingIntent.CanceledException {
        if (!isStartProgress(noti)) {
+6 −21
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static com.android.documentsui.StubProvider.ROOT_0_ID;
import static com.android.documentsui.StubProvider.ROOT_1_ID;

import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -46,18 +45,10 @@ import java.util.concurrent.TimeUnit;
public class CancelFromNotificationUiTest extends ActivityTest<FilesActivity> {
    private static final String TAG = "CancelFromNotificationUiTest";

    private static final String PACKAGE_NAME = "com.android.documentsui.tests";

    private static final String TARGET_FILE = "dummy.data";

    private static final int BUFFER_SIZE = 10 * 1024 * 1024;

    private static final String ACCESS_APP_NAME = "DocumentsUI Tests";

    private static final String COPY = "Copy to…";

    private static final String MOVE = "Move to…";

    private static final int WAIT_TIME_SECONDS = 60;

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -97,10 +88,7 @@ public class CancelFromNotificationUiTest extends ActivityTest<FilesActivity> {
        mDocsHelper.configure(null, bundle);

        try {
            if (!bots.notifications.isNotificationAccessEnabled(
                    context.getContentResolver(), PACKAGE_NAME)) {
                bots.notifications.setNotificationAccess(getActivity(), ACCESS_APP_NAME, true);
            }
            bots.notifications.setNotificationAccess(getActivity(), true);
        } catch (Exception e) {
            Log.d(TAG, "Cannot set notification access. ", e);
        }
@@ -125,10 +113,7 @@ public class CancelFromNotificationUiTest extends ActivityTest<FilesActivity> {

        context.unregisterReceiver(mReceiver);
        try {
            if (bots.notifications.isNotificationAccessEnabled(
                    context.getContentResolver(), PACKAGE_NAME)) {
                bots.notifications.setNotificationAccess(getActivity(), ACCESS_APP_NAME, false);
            }
            bots.notifications.setNotificationAccess(getActivity(), false);
        } catch (Exception e) {
            Log.d(TAG, "Cannot set notification access. ", e);
        }
@@ -164,7 +149,7 @@ public class CancelFromNotificationUiTest extends ActivityTest<FilesActivity> {
        bots.directory.selectDocument(TARGET_FILE, 1);
        device.waitForIdle();

        bots.main.clickToolbarOverflowItem(COPY);
        bots.main.clickToolbarOverflowItem(context.getResources().getString(R.string.menu_copy));
        device.waitForIdle();

        bots.main.clickDialogCancelButton();
@@ -181,7 +166,7 @@ public class CancelFromNotificationUiTest extends ActivityTest<FilesActivity> {
        bots.directory.selectDocument(TARGET_FILE, 1);
        device.waitForIdle();

        bots.main.clickToolbarOverflowItem(COPY);
        bots.main.clickToolbarOverflowItem(context.getResources().getString(R.string.menu_copy));
        device.waitForIdle();

        bots.roots.openRoot(ROOT_1_ID);
@@ -214,7 +199,7 @@ public class CancelFromNotificationUiTest extends ActivityTest<FilesActivity> {
        bots.directory.selectDocument(TARGET_FILE, 1);
        device.waitForIdle();

        bots.main.clickToolbarOverflowItem(MOVE);
        bots.main.clickToolbarOverflowItem(context.getResources().getString(R.string.menu_move));
        device.waitForIdle();

        bots.main.clickDialogCancelButton();
@@ -231,7 +216,7 @@ public class CancelFromNotificationUiTest extends ActivityTest<FilesActivity> {
        bots.directory.selectDocument(TARGET_FILE, 1);
        device.waitForIdle();

        bots.main.clickToolbarOverflowItem(MOVE);
        bots.main.clickToolbarOverflowItem(context.getResources().getString(R.string.menu_move));
        device.waitForIdle();

        bots.roots.openRoot(ROOT_1_ID);
+49 −97
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import static com.android.documentsui.base.Providers.ROOT_ID_DEVICE;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
@@ -30,13 +29,10 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.storage.DiskInfo;
import android.os.storage.StorageManager;
import android.os.SystemClock;
import android.provider.Settings;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.filters.LargeTest;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.util.Log;

import com.android.documentsui.base.DocumentInfo;
@@ -47,7 +43,6 @@ import com.android.documentsui.services.TestNotificationService;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -62,22 +57,8 @@ import java.util.zip.ZipInputStream;
public class FileCopyUiTest extends ActivityTest<FilesActivity> {
    private static final String TAG = "FileCopyUiTest";

    private static final String PACKAGE_NAME = "com.android.documentsui.tests";

    private static final String TARGET_FOLDER = "test_folder";

    private static final String ACCESS_APP_NAME = "DocumentsUI Tests";

    private static final String COPY = "Copy to…";

    private static final String MOVE = "Move to…";

    private static final String SELECT_ALL = "Select all";

    private static final String SHOW_INTERNAL_STORAGE = "Show internal storage";

    private static final String VIRTUAL_LABEL = "Virtual";

    private static final int TARGET_COUNT = 1000;

    private static final int WAIT_TIME_SECONDS = 180;
@@ -96,23 +77,10 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {
                            TestNotificationService.EXTRA_ERROR_REASON);
                }
                mCountDownLatch.countDown();
            } else if (TestNotificationService.ACTION_DISPLAY_SD_CARD_NOTIFICATION.
                    equals(action)) {
                // The notification that is displayed by executing
                // "set-virtual-disk" command may be notified a couple of times.
                // So, it doesn't call CountDownLatch#countDown()
                // if "set-vritual-disk" command already finished.
                if (mSetVirtualDiskFinished.get() == false) {
                    mCountDownLatch.countDown();
                }
            } else if (TestNotificationService.ACTION_SD_CARD_SETTING_COMPLETED.equals(action)) {
                mCountDownLatch.countDown();
            }
        }
    };

    private final AtomicBoolean mSetVirtualDiskFinished = new AtomicBoolean(false);

    private CountDownLatch mCountDownLatch;

    private boolean mOperationExecuted;
@@ -121,8 +89,6 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {

    private DocumentsProviderHelper mStorageDocsHelper;

    private ContentProviderClient mStorageClient;

    private RootInfo mPrimaryRoot;

    private RootInfo mSdCardRoot;
@@ -142,9 +108,9 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {
        super.setUp();

        // Create ContentProviderClient and DocumentsProviderHelper for using SD Card.
        mStorageClient = mResolver.acquireUnstableContentProviderClient(
                AUTHORITY_STORAGE);
        mStorageDocsHelper = new DocumentsProviderHelper(AUTHORITY_STORAGE, mStorageClient);
        ContentProviderClient storageClient =
                mResolver.acquireUnstableContentProviderClient(AUTHORITY_STORAGE);
        mStorageDocsHelper = new DocumentsProviderHelper(AUTHORITY_STORAGE, storageClient);

        // Set a flag to prevent many refreshes.
        Bundle bundle = new Bundle();
@@ -154,27 +120,23 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {
        // Set "Stay awake" until test is finished.
        mPreTestStayAwakeValue = Settings.Global.getInt(context.getContentResolver(),
                Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
        automation.executeShellCommand("settings put global stay_on_while_plugged_in 3");
        device.executeShellCommand("settings put global stay_on_while_plugged_in 3");

        // If Internal Storage is not shown, turn on.
        State state = ((FilesActivity) getActivity()).getDisplayState();
        if (!state.showAdvanced) {
            bots.main.clickToolbarOverflowItem(SHOW_INTERNAL_STORAGE);
            bots.main.clickToolbarOverflowItem(
                    context.getResources().getString(R.string.menu_advanced_show));
        }

        try {
            if (!bots.notifications.isNotificationAccessEnabled(
                    context.getContentResolver(), PACKAGE_NAME)) {
                bots.notifications.setNotificationAccess(getActivity(), ACCESS_APP_NAME, true);
            }
            bots.notifications.setNotificationAccess(getActivity(), true);
        } catch (Exception e) {
            Log.d(TAG, "Cannot set notification access. ", e);
        }

        IntentFilter filter = new IntentFilter();
        filter.addAction(TestNotificationService.ACTION_OPERATION_RESULT);
        filter.addAction(TestNotificationService.ACTION_DISPLAY_SD_CARD_NOTIFICATION);
        filter.addAction(TestNotificationService.ACTION_SD_CARD_SETTING_COMPLETED);
        context.registerReceiver(mReceiver, filter);
        context.sendBroadcast(new Intent(
                TestNotificationService.ACTION_CHANGE_EXECUTION_MODE));
@@ -201,18 +163,15 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {
        deleteDocuments(mSdCardLabel);

        if (mIsVirtualSdCard) {
            automation.executeShellCommand("sm set-virtual-disk false");
            device.executeShellCommand("sm set-virtual-disk false");
        }

        automation.executeShellCommand("settings put global stay_on_while_plugged_in "
        device.executeShellCommand("settings put global stay_on_while_plugged_in "
                + mPreTestStayAwakeValue);

        context.unregisterReceiver(mReceiver);
        try {
            if (bots.notifications.isNotificationAccessEnabled(
                    context.getContentResolver(), PACKAGE_NAME)) {
                bots.notifications.setNotificationAccess(getActivity(), ACCESS_APP_NAME, false);
            }
            bots.notifications.setNotificationAccess(getActivity(), false);
        } catch (Exception e) {
            Log.d(TAG, "Cannot set notification access. ", e);
        }
@@ -263,12 +222,6 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {
            return true;
        }

        if (mCountDownLatch != null) {
            assertTrue("Cannot wait because any operation is waiting now.",
                    mCountDownLatch.getCount() == 0);
        }

        mCountDownLatch = new CountDownLatch(1);
        bots.directory.selectDocument(TARGET_FOLDER, 1);
        device.waitForIdle();

@@ -276,13 +229,7 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {
        bots.main.clickDialogOkButton();
        device.waitForIdle();

        // Wait until copy operation finished
        try {
            mCountDownLatch.await(WAIT_TIME_SECONDS, TimeUnit.SECONDS);
        } catch (Exception e) {
            fail("Error occurs when delete documents. " + e.toString());
        }

        bots.directory.findDocument(TARGET_FOLDER).waitUntilGone(WAIT_TIME_SECONDS);
        return !bots.directory.hasDocuments(TARGET_FOLDER);
    }

@@ -302,10 +249,11 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {
            Resources res) throws Exception {
        ZipInputStream in = null;
        int read = 0;
        int count = 0;
        try {
            in = new ZipInputStream(res.openRawResource(resId));
            ZipEntry zipEntry = null;
            while ((zipEntry = in.getNextEntry()) != null) {
            while ((zipEntry = in.getNextEntry()) != null && (count++ < TARGET_COUNT)) {
                String fileName = zipEntry.getName();
                Uri uri = helper.createDocument(root, "image/png", fileName);
                byte[] buff = new byte[1024];
@@ -329,42 +277,46 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {

    /** @return true if virtual SD Card setting is completed. Othrewise false */
    private boolean enableVirtualSdCard() throws Exception {
        boolean result = false;
        try {
            mSetVirtualDiskFinished.set(false);

            mCountDownLatch = new CountDownLatch(1);
            automation.executeShellCommand("sm set-virtual-disk true");
            boolean result = mCountDownLatch.await(WAIT_TIME_SECONDS, TimeUnit.SECONDS);
            assertTrue("Can't find notification : "
                    + TestNotificationService.UNSUPPORTED_NOTIFICATION_TEXT + " or "
                    + TestNotificationService.CORRUPTED_NOTIFICATION_TEXT,
                    result) ;

            mSetVirtualDiskFinished.set(true);
            device.executeShellCommand("sm set-virtual-disk true");
            String diskId = getAdoptionDisk();
            assertNotNull("Failed to setup virtual disk.", diskId);
            device.executeShellCommand(String.format("sm partition %s public", diskId));
            result = waitForPublicVolume();
        } catch (Exception e) {
            result = false;
        }
        return result;
    }

            String diskId = getDiskId();
            assertNotNull("Can't find Virtual Disk Id", diskId);
    private String getAdoptionDisk() throws Exception {
        int attempt = 0;
        String disks = device.executeShellCommand("sm list-disks adoptable");
        while ((disks == null || disks.isEmpty()) && attempt++ < 15) {
            SystemClock.sleep(1000);
            disks = device.executeShellCommand("sm list-disks adoptable");
        }

            mCountDownLatch = new CountDownLatch(1);
            automation.executeShellCommand(String.format("sm partition %s public", diskId));
            result = mCountDownLatch.await(WAIT_TIME_SECONDS, TimeUnit.SECONDS);
            assertTrue("Can't find notification : " + TestNotificationService.VIRTUAL_SD_CARD_TEXT,
                    result) ;
        } catch (Exception e) {
            return false;
        if (disks == null || disks.isEmpty()) {
            return null;
        }
        return true;
        return disks.split("\n")[0].trim();
    }

    private String getDiskId() throws Exception {
        StorageManager storageManager = context.getSystemService(StorageManager.class);
        final List<DiskInfo> disks = storageManager.getDisks();
        for (DiskInfo disk : disks) {
            if (VIRTUAL_LABEL.equals(disk.label) && disk.isSd()) {
                return disk.getId();
    private boolean waitForPublicVolume() throws Exception {
        int attempt = 0;
        String volumes = device.executeShellCommand("sm list-volumes public");
        while ((volumes == null || volumes.isEmpty() || !volumes.contains("mounted"))
                && attempt++ < 15) {
            SystemClock.sleep(1000);
            volumes = device.executeShellCommand("sm list-volumes public");
        }

        if (volumes == null || volumes.isEmpty()) {
            return false;
        }
        return null;
        return true;
    }

    private void initStorageRootInfo() throws RemoteException {
@@ -385,7 +337,7 @@ public class FileCopyUiTest extends ActivityTest<FilesActivity> {
        bots.roots.openRoot(sourceRoot);
        bots.directory.selectDocument(TARGET_FOLDER, 1);
        device.waitForIdle();
        bots.main.clickToolbarOverflowItem(COPY);
        bots.main.clickToolbarOverflowItem(context.getResources().getString(R.string.menu_copy));
        device.waitForIdle();
        bots.roots.openRoot(targetRoot);
        bots.main.clickDialogOkButton();
+4 −16
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static com.android.documentsui.StubProvider.ROOT_0_ID;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
@@ -48,12 +47,6 @@ import java.util.ArrayList;
public class FileDeleteUiTest extends ActivityTest<FilesActivity> {
    private static final String TAG = "FileDeleteUiTest";

    private static final String PACKAGE_NAME = "com.android.documentsui.tests";

    private static final String ACCESS_APP_NAME = "DocumentsUI Tests";

    private static final String SELECT_ALL = "Select all";

    private static final int DUMMY_FILE_COUNT = 1000;

    private static final int WAIT_TIME_SECONDS = 60;
@@ -96,10 +89,7 @@ public class FileDeleteUiTest extends ActivityTest<FilesActivity> {
        mDocsHelper.configure(null, bundle);

        try {
            if (!bots.notifications.isNotificationAccessEnabled(
                    context.getContentResolver(), PACKAGE_NAME)) {
                bots.notifications.setNotificationAccess(getActivity(), ACCESS_APP_NAME, true);
            }
            bots.notifications.setNotificationAccess(getActivity(), true);
        } catch (Exception e) {
            Log.d(TAG, "Cannot set notification access. ", e);
        }
@@ -124,10 +114,7 @@ public class FileDeleteUiTest extends ActivityTest<FilesActivity> {

        context.unregisterReceiver(mReceiver);
        try {
            if (bots.notifications.isNotificationAccessEnabled(
                    context.getContentResolver(), PACKAGE_NAME)) {
                bots.notifications.setNotificationAccess(getActivity(), ACCESS_APP_NAME, false);
            }
            bots.notifications.setNotificationAccess(getActivity(), false);
        } catch (Exception e) {
            Log.d(TAG, "Cannot set notification access. ", e);
        }
@@ -170,7 +157,8 @@ public class FileDeleteUiTest extends ActivityTest<FilesActivity> {

    public void testDeleteAllDocument() throws Exception {
        bots.roots.openRoot(ROOT_0_ID);
        bots.main.clickToolbarOverflowItem(SELECT_ALL);
        bots.main.clickToolbarOverflowItem(
                context.getResources().getString(R.string.menu_select_all));
        device.waitForIdle();

        bots.main.clickToolbarItem(R.id.action_menu_delete);