Merge "Move directory and roots support to own ui bots." into nyc-dev

This commit is contained in:
Steve McKay
2016-02-22 20:01:46 +00:00
committed by Android (Google) Code Review
15 changed files with 817 additions and 612 deletions

View File

@@ -317,6 +317,12 @@ public abstract class BaseActivity extends Activity
CreateDirectoryFragment.show(getFragmentManager());
}
void onDirectoryCreated(DocumentInfo doc) {
// By default we do nothing, just let the new directory appear.
// DocumentsActivity auto-opens directories after creating them
// As that is more attuned to the "picker" use cases it supports.
}
/**
* Returns true if a directory can be created in the current location.
* @return
@@ -331,11 +337,6 @@ public abstract class BaseActivity extends Activity
&& !root.isDownloads();
}
void onDirectoryCreated(DocumentInfo doc) {
checkArgument(doc.isDirectory());
openContainerDocument(doc);
}
void openContainerDocument(DocumentInfo doc) {
checkArgument(doc.isContainer());
mState.pushDocument(doc);

View File

@@ -23,6 +23,7 @@ import static com.android.documentsui.State.ACTION_OPEN;
import static com.android.documentsui.State.ACTION_OPEN_TREE;
import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
import static com.android.internal.util.Preconditions.checkArgument;
import android.app.Activity;
import android.app.Fragment;
@@ -316,6 +317,12 @@ public class DocumentsActivity extends BaseActivity {
.executeOnExecutor(getExecutorForCurrentDirectory());
}
@Override
void onDirectoryCreated(DocumentInfo doc) {
checkArgument(doc.isDirectory());
openContainerDocument(doc);
}
void onSaveRequested(String mimeType, String displayName) {
new CreateFinishTask(this, mimeType, displayName)
.executeOnExecutor(getExecutorForCurrentDirectory());

View File

@@ -33,7 +33,6 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.util.Log;
import android.view.KeyEvent;

View File

@@ -21,21 +21,22 @@ import static com.android.documentsui.StubProvider.ROOT_0_ID;
import static com.android.documentsui.StubProvider.ROOT_1_ID;
import android.app.Activity;
import android.app.Instrumentation;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.provider.DocumentsContract.Document;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.Configurator;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.Until;
import android.test.ActivityInstrumentationTestCase2;
import android.view.MotionEvent;
import com.android.documentsui.bots.DirectoryListBot;
import com.android.documentsui.bots.KeyboardBot;
import com.android.documentsui.bots.RootsListBot;
import com.android.documentsui.bots.UiBot;
import com.android.documentsui.model.RootInfo;
/**
@@ -56,7 +57,7 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen
public static final String fileName4 = "poodles.text";
public static final String fileNameNoRename = "NO_RENAMEfile.txt";
public UiBot bot;
public Bots bots;
public UiDevice device;
public Context context;
@@ -76,10 +77,11 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen
device = UiDevice.getInstance(getInstrumentation());
// NOTE: Must be the "target" context, else security checks in content provider will fail.
context = getInstrumentation().getTargetContext();
bot = new UiBot(device, context, TIMEOUT);
bots = new Bots(device, context, TIMEOUT);
Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
bot.revealLauncher();
bots.main.revealLauncher();
mResolver = context.getContentResolver();
mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY);
@@ -90,7 +92,7 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen
launchActivity();
bot.revealApp();
bots.main.revealApp();
resetStorage();
}
@@ -125,12 +127,31 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen
}
void assertDefaultContentOfTestDir0() throws UiObjectNotFoundException {
bot.assertDocumentsCount(ROOT_0_ID, 4);
bot.assertHasDocuments(fileName1, fileName2, dirName1, fileNameNoRename);
bots.roots.openRoot(ROOT_0_ID);
bots.directory.assertDocumentsCount(4);
bots.directory.assertDocumentsPresent(fileName1, fileName2, dirName1, fileNameNoRename);
}
void assertDefaultContentOfTestDir1() throws UiObjectNotFoundException {
bot.assertDocumentsCount(ROOT_1_ID, 2);
bot.assertHasDocuments(fileName3, fileName4);
bots.roots.openRoot(ROOT_1_ID);
bots.directory.assertDocumentsCount(2);
bots.directory.assertDocumentsPresent(fileName3, fileName4);
}
/**
* Handy collection of bots for working with Files app.
*/
public static final class Bots {
public final UiBot main;
public final RootsListBot roots;
public final DirectoryListBot directory;
public final KeyboardBot keyboard;
private Bots(UiDevice device, Context context, int timeout) {
this.main = new UiBot(device, context, TIMEOUT);
this.roots = new RootsListBot(device, context, TIMEOUT);
this.directory = new DirectoryListBot(device, context, TIMEOUT);
this.keyboard = new KeyboardBot(device, context, TIMEOUT);
}
}
}

View File

@@ -52,13 +52,13 @@ public class DownloadsActivityUiTest extends ActivityTest<DownloadsActivity> {
public void testWindowTitle() throws Exception {
initTestFiles();
bot.assertWindowTitle(ROOT_0_ID);
bots.main.assertWindowTitle(ROOT_0_ID);
}
public void testFilesListed() throws Exception {
initTestFiles();
bot.assertHasDocuments("file0.log", "file1.png", "file2.csv");
bots.directory.assertDocumentsPresent("file0.log", "file1.png", "file2.csv");
}
public void testFilesList_LiveUpdate() throws Exception {
@@ -66,30 +66,31 @@ public class DownloadsActivityUiTest extends ActivityTest<DownloadsActivity> {
mDocsHelper.createDocument(rootDir0, "yummers/sandwich", "Ham & Cheese.sandwich");
bot.waitForDocument("Ham & Cheese.sandwich");
bot.assertHasDocuments("file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
bots.directory.waitForDocument("Ham & Cheese.sandwich");
bots.directory.assertDocumentsPresent(
"file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
}
public void testDeleteDocument() throws Exception {
initTestFiles();
bot.clickDocument("file1.png");
bots.directory.clickDocument("file1.png");
device.waitForIdle();
bot.menuDelete().click();
bots.main.menuDelete().click();
bot.waitForDeleteSnackbar();
assertFalse(bot.hasDocuments("file1.png"));
bots.directory.waitForDeleteSnackbar();
bots.directory.assertDocumentsAbsent("file1.png");
bot.waitForDeleteSnackbarGone();
assertFalse(bot.hasDocuments("file1.png"));
bots.directory.waitForDeleteSnackbarGone();
bots.directory.assertDocumentsAbsent("file1.png");
}
public void testSupportsShare() throws Exception {
initTestFiles();
bot.clickDocument("file1.png");
bots.directory.clickDocument("file1.png");
device.waitForIdle();
assertNotNull(bot.menuShare());
assertNotNull(bots.main.menuShare());
}
public void testClosesOnBack() throws Exception {

View File

@@ -43,11 +43,11 @@ public class FilesActivityUiTest extends ActivityTest<FilesActivity> {
public void testRootsListed() throws Exception {
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
// Should also have Drive, but that requires pre-configuration of devices
// We omit for now.
bot.assertHasRoots(
bots.roots.assertHasRoots(
"Images",
"Videos",
"Audio",
@@ -60,93 +60,106 @@ public class FilesActivityUiTest extends ActivityTest<FilesActivity> {
public void testFilesListed() throws Exception {
initTestFiles();
bot.openRoot(ROOT_0_ID);
bot.assertHasDocuments("file0.log", "file1.png", "file2.csv");
bots.roots.openRoot(ROOT_0_ID);
bots.directory.assertDocumentsPresent("file0.log", "file1.png", "file2.csv");
}
public void testLoadsHomeDirectoryByDefault() throws Exception {
initTestFiles();
device.waitForIdle();
bot.assertWindowTitle("Documents");
bots.main.assertWindowTitle("Documents");
}
public void testRootClickSetsWindowTitle() throws Exception {
initTestFiles();
bot.openRoot("Downloads");
bot.assertWindowTitle("Downloads");
bots.roots.openRoot("Downloads");
bots.main.assertWindowTitle("Downloads");
}
public void testFilesList_LiveUpdate() throws Exception {
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
mDocsHelper.createDocument(rootDir0, "yummers/sandwich", "Ham & Cheese.sandwich");
bot.waitForDocument("Ham & Cheese.sandwich");
bot.assertHasDocuments("file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
bots.directory.waitForDocument("Ham & Cheese.sandwich");
bots.directory.assertDocumentsPresent(
"file0.log", "file1.png", "file2.csv", "Ham & Cheese.sandwich");
}
public void testCreateDirectory() throws Exception {
initTestFiles();
bots.main.openOverflowMenu();
bots.main.menuNewFolder().click();
bots.main.setDialogText("Kung Fu Panda");
bots.keyboard.pressEnter();
bots.directory.assertDocumentsPresent("Kung Fu Panda");
}
public void testDeleteDocument() throws Exception {
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
bot.clickDocument("file1.png");
bots.directory.clickDocument("file1.png");
device.waitForIdle();
bot.menuDelete().click();
bots.main.menuDelete().click();
bot.waitForDeleteSnackbar();
assertFalse(bot.hasDocuments("file1.png"));
bots.directory.waitForDeleteSnackbar();
bots.directory.assertDocumentsAbsent("file1.png");
bot.waitForDeleteSnackbarGone();
assertFalse(bot.hasDocuments("file1.png"));
bots.directory.waitForDeleteSnackbarGone();
bots.directory.assertDocumentsAbsent("file1.png");
// Now delete from another root.
bot.openRoot(ROOT_1_ID);
bots.roots.openRoot(ROOT_1_ID);
bot.clickDocument("poodles.text");
bots.directory.clickDocument("poodles.text");
device.waitForIdle();
bot.menuDelete().click();
bots.main.menuDelete().click();
bot.waitForDeleteSnackbar();
assertFalse(bot.hasDocuments("poodles.text"));
bots.directory.waitForDeleteSnackbar();
bots.directory.assertDocumentsAbsent("poodles.text");
bot.waitForDeleteSnackbarGone();
assertFalse(bot.hasDocuments("poodles.text"));
bots.directory.waitForDeleteSnackbarGone();
bots.directory.assertDocumentsAbsent("poodles.text");
}
// Tests that pressing tab switches focus between the roots and directory listings.
public void testKeyboard_tab() throws Exception {
bot.pressKey(KeyEvent.KEYCODE_TAB);
bot.assertHasFocus("com.android.documentsui:id/roots_list");
bot.pressKey(KeyEvent.KEYCODE_TAB);
bot.assertHasFocus("com.android.documentsui:id/dir_list");
bots.main.pressKey(KeyEvent.KEYCODE_TAB);
bots.roots.assertHasFocus();
bots.main.pressKey(KeyEvent.KEYCODE_TAB);
bots.directory.assertHasFocus();
}
// Tests that arrow keys do not switch focus away from the dir list.
public void testKeyboard_arrowsDirList() throws Exception {
for (int i = 0; i < 10; i++) {
bot.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
bot.assertHasFocus("com.android.documentsui:id/dir_list");
bots.main.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
bots.directory.assertHasFocus();
}
for (int i = 0; i < 10; i++) {
bot.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
bot.assertHasFocus("com.android.documentsui:id/dir_list");
bots.main.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
bots.directory.assertHasFocus();
}
}
// Tests that arrow keys do not switch focus away from the roots list.
public void testKeyboard_arrowsRootsList() throws Exception {
bot.pressKey(KeyEvent.KEYCODE_TAB);
bots.main.pressKey(KeyEvent.KEYCODE_TAB);
for (int i = 0; i < 10; i++) {
bot.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
bot.assertHasFocus("com.android.documentsui:id/roots_list");
bots.main.pressKey(KeyEvent.KEYCODE_DPAD_RIGHT);
bots.roots.assertHasFocus();
}
for (int i = 0; i < 10; i++) {
bot.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
bot.assertHasFocus("com.android.documentsui:id/roots_list");
bots.main.pressKey(KeyEvent.KEYCODE_DPAD_LEFT);
bots.roots.assertHasFocus();
}
}
}

View File

@@ -23,8 +23,6 @@ import android.test.suitebuilder.annotation.LargeTest;
@LargeTest
public class RenameDocumentUiTest extends ActivityTest<FilesActivity> {
private static final String TAG = "RenamDocumentUiTest";
private final String newName = "kitties.log";
public RenameDocumentUiTest() {
@@ -35,125 +33,119 @@ public class RenameDocumentUiTest extends ActivityTest<FilesActivity> {
public void setUp() throws Exception {
super.setUp();
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
}
public void testRenameEnabled_SingleSelection() throws Exception {
bot.selectDocument(fileName1);
bot.openOverflowMenu();
bot.assertMenuEnabled(R.string.menu_rename, true);
bots.directory.selectDocument(fileName1);
bots.main.openOverflowMenu();
bots.main.assertMenuEnabled(R.string.menu_rename, true);
// Dismiss more options window
device.pressBack();
}
public void testNoRenameSupport_SingleSelection() throws Exception {
bot.selectDocument(fileNameNoRename);
bot.openOverflowMenu();
bot.assertMenuEnabled(R.string.menu_rename, false);
bots.directory.selectDocument(fileNameNoRename);
bots.main.openOverflowMenu();
bots.main.assertMenuEnabled(R.string.menu_rename, false);
// Dismiss more options window
device.pressBack();
}
public void testOneHasRenameSupport_MultipleSelection() throws Exception {
bot.selectDocument(fileName1);
bot.selectDocument(fileNameNoRename);
bot.openOverflowMenu();
bot.assertMenuEnabled(R.string.menu_rename, false);
bots.directory.selectDocument(fileName1);
bots.directory.selectDocument(fileNameNoRename);
bots.main.openOverflowMenu();
bots.main.assertMenuEnabled(R.string.menu_rename, false);
// Dismiss more options window
device.pressBack();
}
public void testRenameDisabled_MultipleSelection() throws Exception {
bot.selectDocument(fileName1);
bot.selectDocument(fileName2);
bot.openOverflowMenu();
bot.assertMenuEnabled(R.string.menu_rename, false);
bots.directory.selectDocument(fileName1);
bots.directory.selectDocument(fileName2);
bots.main.openOverflowMenu();
bots.main.assertMenuEnabled(R.string.menu_rename, false);
// Dismiss more options window
device.pressBack();
}
public void testRenameFile_OkButton() throws Exception {
bot.selectDocument(fileName1);
bot.openOverflowMenu();
bot.openDialog(R.string.menu_rename);
bot.setDialogText(newName);
bots.directory.selectDocument(fileName1);
bots.main.openOverflowMenu();
bots.main.menuRename().click();
bots.main.setDialogText(newName);
device.waitForIdle(TIMEOUT);
bot.findRenameDialogOkButton().click();
bots.main.findRenameDialogOkButton().click();
device.waitForIdle(TIMEOUT);
bot.assertDocument(fileName1, false);
bot.assertDocument(newName, true);
bot.assertDocumentsCount(4);
bots.directory.assertDocumentsAbsent(fileName1);
bots.directory.assertDocumentsPresent(newName);
bots.directory.assertDocumentsCount(4);
}
public void testRenameFile_Enter() throws Exception {
bot.selectDocument(fileName1);
bot.openOverflowMenu();
bot.openDialog(R.string.menu_rename);
bot.setDialogText(newName);
bots.directory.selectDocument(fileName1);
bots.main.openOverflowMenu();
bots.main.menuRename().click();
bots.main.setDialogText(newName);
pressEnter();
bots.keyboard.pressEnter();
bot.assertDocument(fileName1, false);
bot.assertDocument(newName, true);
bot.assertDocumentsCount(4);
bots.directory.assertDocumentsAbsent(fileName1);
bots.directory.assertDocumentsPresent(newName);
bots.directory.assertDocumentsCount(4);
}
public void testRenameFile_Cancel() throws Exception {
bot.selectDocument(fileName1);
bot.openOverflowMenu();
bot.openDialog(R.string.menu_rename);
bot.setDialogText(newName);
bots.directory.selectDocument(fileName1);
bots.main.openOverflowMenu();
bots.main.menuRename().click();
bots.main.setDialogText(newName);
device.waitForIdle(TIMEOUT);
bot.findRenameDialogCancelButton().click();
bots.main.findRenameDialogCancelButton().click();
device.waitForIdle(TIMEOUT);
bot.assertDocument(fileName1, true);
bot.assertDocument(newName, false);
bot.assertDocumentsCount(4);
bots.directory.assertDocumentsPresent(fileName1);
bots.directory.assertDocumentsAbsent(newName);
bots.directory.assertDocumentsCount(4);
}
public void testRenameDir() throws Exception {
String oldName = "Dir1";
String newName = "Dir123";
bot.selectDocument(oldName);
bot.openOverflowMenu();
bot.openDialog(R.string.menu_rename);
bot.setDialogText(newName);
bots.directory.selectDocument(oldName);
bots.main.openOverflowMenu();
bots.main.menuRename().click();
bots.main.setDialogText(newName);
pressEnter();
bots.keyboard.pressEnter();
bot.assertDocument(oldName, false);
bot.assertDocument(newName, true);
bot.assertDocumentsCount(4);
bots.directory.assertDocumentsAbsent(oldName);
bots.directory.assertDocumentsPresent(newName);
bots.directory.assertDocumentsCount(4);
}
public void testRename_NameExists() throws Exception {
// Check that document with the new name exists
bot.assertDocument(fileName2, true);
bot.selectDocument(fileName1);
bot.openOverflowMenu();
bot.openDialog(R.string.menu_rename);
bot.setDialogText(fileName2);
bots.directory.assertDocumentsPresent(fileName2);
bots.directory.selectDocument(fileName1);
bots.main.openOverflowMenu();
bots.main.menuRename().click();
bots.main.setDialogText(fileName2);
pressEnter();
bots.keyboard.pressEnter();
bot.assertSnackbar(R.string.rename_error);
bot.assertDocument(fileName1, true);
bot.assertDocument(fileName2, true);
bot.assertDocumentsCount(4);
}
private void pressEnter() {
device.waitForIdle(TIMEOUT);
device.pressEnter();
device.waitForIdle(TIMEOUT);
bots.directory.assertSnackbar(R.string.rename_error);
bots.directory.assertDocumentsPresent(fileName1);
bots.directory.assertDocumentsPresent(fileName2);
bots.directory.assertDocumentsCount(4);
}
}

View File

@@ -18,19 +18,14 @@ package com.android.documentsui;
import static com.android.documentsui.StubProvider.ROOT_0_ID;
import android.support.test.uiautomator.Configurator;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import android.view.MotionEvent;
@LargeTest
public class RootUiTest extends ActivityTest<FilesActivity> {
public class RootsUiTest extends ActivityTest<FilesActivity> {
private static final String TAG = "RootUiTest";
public RootUiTest() {
public RootsUiTest() {
super(FilesActivity.class);
}
@@ -38,14 +33,14 @@ public class RootUiTest extends ActivityTest<FilesActivity> {
public void setUp() throws Exception {
super.setUp();
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
}
public void testRootTapped_GoToRootFromChildDir() throws Exception {
bot.openDocument(dirName1);
bot.assertWindowTitle(dirName1);
bot.openRoot(ROOT_0_ID);
bot.assertWindowTitle(ROOT_0_ID);
bots.directory.openDocument(dirName1);
bots.main.assertWindowTitle(dirName1);
bots.roots.openRoot(ROOT_0_ID);
bots.main.assertWindowTitle(ROOT_0_ID);
assertDefaultContentOfTestDir0();
}
}

View File

@@ -24,61 +24,59 @@ import android.test.suitebuilder.annotation.LargeTest;
@LargeTest
public class SearchViewUiTest extends ActivityTest<FilesActivity> {
private static final String TAG = "SearchViewUiTest";
public SearchViewUiTest() {
super(FilesActivity.class);
}
public void testSearchView_ExpandsOnClick() throws Exception {
bot.openSearchView();
bot.assertSearchTextFiledAndIcon(true, false);
bots.main.openSearchView();
bots.main.assertSearchTextFiledAndIcon(true, false);
}
public void testSearchView_CollapsesOnBack() throws Exception {
bot.openSearchView();
bots.main.openSearchView();
device.pressBack();
bot.assertSearchTextFiledAndIcon(false, true);
bots.main.assertSearchTextFiledAndIcon(false, true);
}
public void testSearchView_ClearsTextOnBack() throws Exception {
String query = "file2";
bot.openSearchView();
bot.setSearchQuery(query);
bots.main.openSearchView();
bots.main.setSearchQuery(query);
device.pressBack();
bot.assertSearchTextFiledAndIcon(false, true);
bots.main.assertSearchTextFiledAndIcon(false, true);
}
public void testSearch_ResultsFound() throws Exception {
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
assertDefaultContentOfTestDir0();
String query = "file1";
bot.openSearchView();
bot.setSearchQuery(query);
bot.assertSearchTextField(true, query);
bots.main.openSearchView();
bots.main.setSearchQuery(query);
bots.main.assertSearchTextField(true, query);
device.pressEnter();
bot.assertDocumentsCountOnList(true, 2);
bot.assertHasDocuments(fileName1, fileName2);
bots.directory.assertDocumentsCountOnList(true, 2);
bots.directory.assertDocumentsPresent(fileName1, fileName2);
bot.assertSearchTextField(false, query);
bots.main.assertSearchTextField(false, query);
}
public void testSearchResultsFound_ClearsOnBack() throws Exception {
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
assertDefaultContentOfTestDir0();
String query = fileName1;
bot.openSearchView();
bot.setSearchQuery(query);
bots.main.openSearchView();
bots.main.setSearchQuery(query);
device.pressEnter();
device.pressBack();
@@ -88,32 +86,32 @@ public class SearchViewUiTest extends ActivityTest<FilesActivity> {
public void testSearch_NoResults() throws Exception {
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
assertDefaultContentOfTestDir0();
String query = "chocolate";
bot.openSearchView();
bot.setSearchQuery(query);
bots.main.openSearchView();
bots.main.setSearchQuery(query);
device.pressEnter();
bot.assertDocumentsCountOnList(false, 0);
bots.directory.assertDocumentsCountOnList(false, 0);
device.waitForIdle();
String msg = String.valueOf(context.getString(R.string.no_results));
bot.assertMessageTextView(String.format(msg, "TEST_ROOT_0"));
bots.directory.assertMessageTextView(String.format(msg, "TEST_ROOT_0"));
bot.assertSearchTextField(false, query);
bots.main.assertSearchTextField(false, query);
}
public void testSearchNoResults_ClearsOnBack() throws Exception {
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
assertDefaultContentOfTestDir0();
String query = "chocolate";
bot.openSearchView();
bot.setSearchQuery(query);
bots.main.openSearchView();
bots.main.setSearchQuery(query);
device.pressEnter();
device.pressBack();
@@ -124,30 +122,30 @@ public class SearchViewUiTest extends ActivityTest<FilesActivity> {
public void testSearchResultsFound_ClearsOnDirectoryChange() throws Exception {
initTestFiles();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
assertDefaultContentOfTestDir0();
String query = fileName1;
bot.openSearchView();
bot.setSearchQuery(query);
bots.main.openSearchView();
bots.main.setSearchQuery(query);
device.pressEnter();
bot.openRoot(ROOT_1_ID);
bots.roots.openRoot(ROOT_1_ID);
assertDefaultContentOfTestDir1();
bot.openRoot(ROOT_0_ID);
bots.roots.openRoot(ROOT_0_ID);
assertDefaultContentOfTestDir0();
}
public void testSearchIconVisible_RootWithSearchSupport() throws Exception {
bot.openRoot(ROOT_0_ID);
bot.assertSearchTextFiledAndIcon(false, true);
bots.roots.openRoot(ROOT_0_ID);
bots.main.assertSearchTextFiledAndIcon(false, true);
}
public void testSearchIconHidden_RootNoSearchSupport() throws Exception {
bot.openRoot(ROOT_1_ID);
bot.assertSearchTextFiledAndIcon(false, false);
bots.roots.openRoot(ROOT_1_ID);
bots.main.assertSearchTextFiledAndIcon(false, false);
}
}

View File

@@ -1,432 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.documentsui;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.assertFalse;
import android.app.Activity;
import android.content.Context;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Configurator;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.util.Log;
import android.view.MotionEvent;
import android.view.inputmethod.InputMethodManager;
import junit.framework.Assert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
/**
* A test helper class that provides support for controlling DocumentsUI activities
* programmatically, and making assertions against the state of the UI.
*/
class UiBot {
public static final String TARGET_PKG = "com.android.documentsui";
private static final String TAG = "UiBot";
private static final String LAUNCHER_PKG = "com.android.launcher";
private static final BySelector SNACK_DELETE =
By.desc(Pattern.compile("^Deleting [0-9]+ file.+"));
private UiDevice mDevice;
private Context mContext;
private int mTimeout;
public UiBot(UiDevice device, Context context, int timeout) {
mDevice = device;
mContext = context;
mTimeout = timeout;
}
UiObject findRoot(String label) throws UiObjectNotFoundException {
final UiSelector rootsList = new UiSelector().resourceId(
"com.android.documentsui:id/container_roots").childSelector(
new UiSelector().resourceId("com.android.documentsui:id/roots_list"));
// We might need to expand drawer if not visible
if (!new UiObject(rootsList).waitForExists(mTimeout)) {
Log.d(TAG, "Failed to find roots list; trying to expand");
final UiSelector hamburger = new UiSelector().resourceId(
"com.android.documentsui:id/toolbar").childSelector(
new UiSelector().className("android.widget.ImageButton").clickable(true));
new UiObject(hamburger).click();
}
// Wait for the first list item to appear
new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(mTimeout);
// Now scroll around to find our item
new UiScrollable(rootsList).scrollIntoView(new UiSelector().text(label));
return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
}
void openRoot(String label) throws UiObjectNotFoundException {
findRoot(label).click();
mDevice.waitForIdle();
}
void assertWindowTitle(String expected) {
// Turns out the title field on a window does not have
// an id associated with it at runtime (which confuses the hell out of me)
// In code we address this via "android.R.id.title".
UiObject2 o = find(By.text(expected));
// It's a bit of a conceit that we then *assert* that the title
// is the value that we used to identify the UiObject2.
// If the preceeding lookup fails, this'll choke with an NPE.
// But given the issue described in the comment above, we're
// going to do it anyway. Because we shouldn't be looking up
// the uiobject by it's expected content :|
assertEquals(expected, o.getText());
}
void assertHasRoots(String... labels) throws UiObjectNotFoundException {
List<String> missing = new ArrayList<>();
for (String label : labels) {
if (!findRoot(label).exists()) {
missing.add(label);
}
}
if (!missing.isEmpty()) {
Assert.fail(
"Expected roots " + Arrays.asList(labels) + ", but missing " + missing);
}
}
void assertMenuEnabled(int id, boolean enabled) {
UiObject2 menu= findMenuWithName(mContext.getString(id));
assertNotNull(menu);
assertEquals(enabled, menu.isEnabled());
}
void assertDocumentsCount(int count) throws UiObjectNotFoundException {
UiObject docsList = findDocumentsList();
assertEquals(count, docsList.getChildCount());
}
void assertDocumentsCount(String dir, int count) throws UiObjectNotFoundException {
openRoot(dir);
UiObject docsList = findDocumentsList();
assertEquals(count, docsList.getChildCount());
}
void assertSearchTextField(boolean isFocused, String query)
throws UiObjectNotFoundException {
UiObject textField = findSearchViewTextField();
UiObject searchIcon = findSearchViewIcon();
assertFalse(searchIcon.exists());
assertTrue(textField.exists());
assertEquals(isFocused, textField.isFocused());
if(query != null) {
assertEquals(query, textField.getText());
}
}
void assertSearchTextFiledAndIcon(boolean searchTextFieldExists, boolean searchIconExists) {
assertEquals(searchTextFieldExists, findSearchViewTextField().exists());
assertEquals(searchIconExists, findSearchViewIcon().exists());
}
void assertHasDocuments(String... labels) throws UiObjectNotFoundException {
List<String> missing = new ArrayList<>();
for (String label : labels) {
if (!findDocument(label).exists()) {
missing.add(label);
}
}
if (!missing.isEmpty()) {
Assert.fail(
"Expected documents " + Arrays.asList(labels) + ", but missing " + missing);
}
}
void assertDocument(String name, boolean exists) throws UiObjectNotFoundException {
UiObject doc = findDocument(name);
assertEquals(exists, doc.exists());
}
void assertDocumentsCountOnList(boolean exists, int count) throws UiObjectNotFoundException {
UiObject docsList = findDocumentsList();
assertEquals(exists, docsList.exists());
if(docsList.exists()) {
assertEquals(count, docsList.getChildCount());
}
}
void assertMessageTextView(String message) throws UiObjectNotFoundException {
UiObject messageTextView = findMessageTextView();
assertTrue(messageTextView.exists());
String msg = String.valueOf(message);
assertEquals(String.format(msg, "TEST_ROOT_0"), messageTextView.getText());
}
void assertSnackbar(int id) {
assertNotNull(getSnackbar(mContext.getString(id)));
}
/**
* Asserts that the specified view or one of its descendents has focus.
*/
void assertHasFocus(String resourceName) {
UiObject2 candidate = mDevice.findObject(By.res(resourceName));
assertNotNull("Expected " + resourceName + " to have focus, but it didn't.",
candidate.findObject(By.focused(true)));
}
void openDocument(String label) throws UiObjectNotFoundException {
int toolType = Configurator.getInstance().getToolType();
Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
UiObject doc = findDocument(label);
doc.click();
Configurator.getInstance().setToolType(toolType);
}
void clickDocument(String label) throws UiObjectNotFoundException {
findDocument(label).click();
}
void openSearchView() throws UiObjectNotFoundException {
UiObject searchView = findSearchView();
searchView.click();
assertTrue(searchView.exists());
}
void setSearchQuery(String query) throws UiObjectNotFoundException {
UiObject searchView = findSearchView();
assertTrue(searchView.exists());
UiObject searchTextField = findSearchViewTextField();
searchTextField.setText(query);
assertSearchTextField(true, query);
}
UiObject openOverflowMenu() throws UiObjectNotFoundException {
UiObject obj = findMenuMoreOptions();
obj.click();
mDevice.waitForIdle(mTimeout);
return obj;
}
void openDialog(int id) {
UiObject2 menu= findMenuWithName(mContext.getString(id));
assertNotNull(menu);
assertEquals(true, menu.isEnabled());
menu.click();
}
void setDialogText(String text) throws UiObjectNotFoundException {
findDialogEditText().setText(text);
}
UiObject selectDocument(String label) throws UiObjectNotFoundException {
UiObject doc = findDocument(label);
doc.longClick();
return doc;
}
UiObject2 getSnackbar(String message) {
return mDevice.wait(Until.findObject(By.text(message)), mTimeout);
}
void waitForDeleteSnackbar() {
mDevice.wait(Until.findObject(SNACK_DELETE), mTimeout);
}
void waitForDeleteSnackbarGone() {
// wait a little longer for snackbar to go away, as it disappears after a timeout.
mDevice.wait(Until.gone(SNACK_DELETE), mTimeout * 2);
}
void waitForDocument(String label) throws UiObjectNotFoundException {
findDocument(label).waitForExists(mTimeout);
}
void switchViewMode() {
UiObject2 mode = menuGridMode();
if (mode != null) {
mode.click();
} else {
menuListMode().click();
}
}
UiObject2 menuGridMode() {
// Note that we're using By.desc rather than By.res, because of b/25285770
return find(By.desc("Grid view"));
}
UiObject2 menuListMode() {
// Note that we're using By.desc rather than By.res, because of b/25285770
return find(By.desc("List view"));
}
UiObject2 menuDelete() {
return find(By.res("com.android.documentsui:id/menu_delete"));
}
UiObject2 menuShare() {
return find(By.res("com.android.documentsui:id/menu_share"));
}
private UiObject2 find(BySelector selector) {
mDevice.wait(Until.findObject(selector), mTimeout);
return mDevice.findObject(selector);
}
private UiObject findObject(String resourceId) {
final UiSelector object = new UiSelector().resourceId(resourceId);
return mDevice.findObject(object);
}
private UiObject findObject(String parentResourceId, String childResourceId) {
final UiSelector selector = new UiSelector()
.resourceId(parentResourceId)
.childSelector(new UiSelector().resourceId(childResourceId));
return mDevice.findObject(selector);
}
UiObject findDocument(String label) throws UiObjectNotFoundException {
final UiSelector docList = new UiSelector().resourceId(
"com.android.documentsui:id/container_directory").childSelector(
new UiSelector().resourceId("com.android.documentsui:id/dir_list"));
// Wait for the first list item to appear
new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout);
// new UiScrollable(docList).scrollIntoView(new UiSelector().text(label));
return mDevice.findObject(docList.childSelector(new UiSelector().text(label)));
}
boolean hasDocuments(String... labels) throws UiObjectNotFoundException {
for (String label : labels) {
if (!findDocument(label).exists()) {
return false;
}
}
return true;
}
UiObject findDocumentsList() {
return findObject(
"com.android.documentsui:id/container_directory",
"com.android.documentsui:id/dir_list");
}
UiObject findSearchView() {
return findObject("com.android.documentsui:id/menu_search");
}
UiObject findSearchViewTextField() {
return findObject("com.android.documentsui:id/menu_search", "android:id/search_src_text");
}
UiObject findSearchViewIcon() {
return findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
}
UiObject findMessageTextView() {
return findObject(
"com.android.documentsui:id/container_directory",
"com.android.documentsui:id/message");
}
UiObject findActionModeBar() {
return findObject("android:id/action_mode_bar");
}
UiObject findDialogEditText() {
return findObject("android:id/content", "android:id/text1");
}
UiObject findRenameDialogOkButton() {
return findObject("android:id/content", "android:id/button1");
}
UiObject findRenameDialogCancelButton() {
return findObject("android:id/content", "android:id/button2");
}
UiObject findMenuLabelWithName(String label) {
UiSelector selector = new UiSelector().text(label);
return mDevice.findObject(selector);
}
UiObject2 findMenuWithName(String label) {
List<UiObject2> menuItems = mDevice.findObjects(By.clazz("android.widget.LinearLayout"));
Iterator<UiObject2> it = menuItems.iterator();
UiObject2 menuItem = null;
while(it.hasNext()) {
menuItem = it.next();
UiObject2 text = menuItem.findObject(By.text(label));
if(text != null) {
break;
}
}
return menuItem;
}
UiObject findMenuMoreOptions() {
UiSelector selector = new UiSelector().className("android.widget.ImageButton")
.descriptionContains("More options");
//TODO: use the system string ? android.R.string.action_menu_overflow_description
return mDevice.findObject(selector);
}
// Indirect way to detect the keyboard.
boolean isKeyboardPresent() {
InputMethodManager inputManager = (InputMethodManager) mContext
.getSystemService(Context.INPUT_METHOD_SERVICE);
return inputManager.isAcceptingText();
}
void dismissKeyboardIfPresent() {
if(isKeyboardPresent()) {
mDevice.pressBack();
}
}
void revealLauncher() {
mDevice.pressHome();
mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), mTimeout);
}
void revealApp() {
mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), mTimeout);
mDevice.waitForIdle();
}
void pressKey(int keyCode) {
mDevice.pressKeyCode(keyCode);
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.documentsui.bots;
import static junit.framework.Assert.assertNotNull;
import android.content.Context;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
/**
* A test helper class that provides support for controlling directory list
* and making assertions against the state of it.
*/
abstract class BaseBot {
final UiDevice mDevice;
final Context mContext;
final int mTimeout;
BaseBot(UiDevice device, Context context, int timeout) {
mDevice = device;
mContext = context;
mTimeout = timeout;
}
/**
* Asserts that the specified view or one of its descendents has focus.
*/
protected void assertHasFocus(String resourceName) {
UiObject2 candidate = mDevice.findObject(By.res(resourceName));
assertNotNull("Expected " + resourceName + " to have focus, but it didn't.",
candidate.findObject(By.focused(true)));
}
protected UiObject2 find(BySelector selector) {
mDevice.wait(Until.findObject(selector), mTimeout);
return mDevice.findObject(selector);
}
protected UiObject findObject(String resourceId) {
final UiSelector object = new UiSelector().resourceId(resourceId);
return mDevice.findObject(object);
}
protected UiObject findObject(String parentResourceId, String childResourceId) {
final UiSelector selector = new UiSelector()
.resourceId(parentResourceId)
.childSelector(new UiSelector().resourceId(childResourceId));
return mDevice.findObject(selector);
}
protected void waitForIdle() {
mDevice.waitForIdle(mTimeout);
}
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.documentsui.bots;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import android.content.Context;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Configurator;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.view.MotionEvent;
import junit.framework.Assert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
/**
* A test helper class that provides support for controlling directory list
* and making assertions against the state of it.
*/
public class DirectoryListBot extends BaseBot {
private static final String DIR_LIST_ID = "com.android.documentsui:id/dir_list";
private static final BySelector SNACK_DELETE =
By.desc(Pattern.compile("^Deleting [0-9]+ file.+"));
public DirectoryListBot(UiDevice device, Context context, int timeout) {
super(device, context, timeout);
}
public void assertDocumentsCount(int count) throws UiObjectNotFoundException {
UiObject docsList = findDocumentsList();
assertEquals(count, docsList.getChildCount());
}
public void assertDocumentsPresent(String... labels) throws UiObjectNotFoundException {
List<String> absent = new ArrayList<>();
for (String label : labels) {
if (!findDocument(label).exists()) {
absent.add(label);
}
}
if (!absent.isEmpty()) {
Assert.fail("Expected documents " + Arrays.asList(labels)
+ ", but missing " + absent);
}
}
public void assertDocumentsAbsent(String... labels) throws UiObjectNotFoundException {
List<String> found = new ArrayList<>();
for (String label : labels) {
if (findDocument(label).exists()) {
found.add(label);
}
}
if (!found.isEmpty()) {
Assert.fail("Expected documents not present" + Arrays.asList(labels)
+ ", but present " + found);
}
}
public void assertDocumentsCountOnList(boolean exists, int count) throws UiObjectNotFoundException {
UiObject docsList = findDocumentsList();
assertEquals(exists, docsList.exists());
if(docsList.exists()) {
assertEquals(count, docsList.getChildCount());
}
}
public void assertMessageTextView(String message) throws UiObjectNotFoundException {
UiObject messageTextView = findMessageTextView();
assertTrue(messageTextView.exists());
String msg = String.valueOf(message);
assertEquals(String.format(msg, "TEST_ROOT_0"), messageTextView.getText());
}
private UiObject findMessageTextView() {
return findObject(
"com.android.documentsui:id/container_directory",
"com.android.documentsui:id/message");
}
public void assertSnackbar(int id) {
assertNotNull(getSnackbar(mContext.getString(id)));
}
public void openDocument(String label) throws UiObjectNotFoundException {
int toolType = Configurator.getInstance().getToolType();
Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
UiObject doc = findDocument(label);
doc.click();
Configurator.getInstance().setToolType(toolType);
}
public void clickDocument(String label) throws UiObjectNotFoundException {
findDocument(label).click();
}
public UiObject selectDocument(String label) throws UiObjectNotFoundException {
UiObject doc = findDocument(label);
doc.longClick();
return doc;
}
public UiObject2 getSnackbar(String message) {
return mDevice.wait(Until.findObject(By.text(message)), mTimeout);
}
public void waitForDeleteSnackbar() {
mDevice.wait(Until.findObject(SNACK_DELETE), mTimeout);
}
public void waitForDeleteSnackbarGone() {
// wait a little longer for snackbar to go away, as it disappears after a timeout.
mDevice.wait(Until.gone(SNACK_DELETE), mTimeout * 2);
}
public void waitForDocument(String label) throws UiObjectNotFoundException {
findDocument(label).waitForExists(mTimeout);
}
public UiObject findDocument(String label) throws UiObjectNotFoundException {
final UiSelector docList = new UiSelector().resourceId(
"com.android.documentsui:id/container_directory").childSelector(
new UiSelector().resourceId(DIR_LIST_ID));
// Wait for the first list item to appear
new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout);
// new UiScrollable(docList).scrollIntoView(new UiSelector().text(label));
return mDevice.findObject(docList.childSelector(new UiSelector().text(label)));
}
public boolean hasDocuments(String... labels) throws UiObjectNotFoundException {
for (String label : labels) {
if (!findDocument(label).exists()) {
return false;
}
}
return true;
}
private UiObject findDocumentsList() {
return findObject(
"com.android.documentsui:id/container_directory",
DIR_LIST_ID);
}
public void assertHasFocus() {
assertHasFocus(DIR_LIST_ID);
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.documentsui.bots;
import android.content.Context;
import android.support.test.uiautomator.UiDevice;
import android.view.inputmethod.InputMethodManager;
/**
* A test helper class that provides support for keyboard manipulation.
*/
public class KeyboardBot extends BaseBot {
public KeyboardBot(UiDevice device, Context context, int timeout) {
super(device, context, timeout);
}
public void dismissKeyboardIfPresent() {
if(isKeyboardPresent()) {
mDevice.pressBack();
}
}
// Indirect way to detect the keyboard.
private boolean isKeyboardPresent() {
InputMethodManager inputManager = (InputMethodManager) mContext
.getSystemService(Context.INPUT_METHOD_SERVICE);
return inputManager.isAcceptingText();
}
public void pressEnter() {
waitForIdle();
mDevice.pressEnter();
waitForIdle();
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.documentsui.bots;
import android.content.Context;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiScrollable;
import android.support.test.uiautomator.UiSelector;
import android.util.Log;
import junit.framework.Assert;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A test helper class that provides support for controlling and asserting against
* the roots list drawer.
*/
public class RootsListBot extends BaseBot {
private static final String ROOTS_LIST_ID = "com.android.documentsui:id/roots_list";
private static final String TAG = "RootsListBot";
public RootsListBot(UiDevice device, Context context, int timeout) {
super(device, context, timeout);
}
private UiObject findRoot(String label) throws UiObjectNotFoundException {
final UiSelector rootsList = new UiSelector().resourceId(
"com.android.documentsui:id/container_roots").childSelector(
new UiSelector().resourceId(ROOTS_LIST_ID));
// We might need to expand drawer if not visible
if (!new UiObject(rootsList).waitForExists(mTimeout)) {
Log.d(TAG, "Failed to find roots list; trying to expand");
final UiSelector hamburger = new UiSelector().resourceId(
"com.android.documentsui:id/toolbar").childSelector(
new UiSelector().className("android.widget.ImageButton").clickable(true));
new UiObject(hamburger).click();
}
// Wait for the first list item to appear
new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(mTimeout);
// Now scroll around to find our item
new UiScrollable(rootsList).scrollIntoView(new UiSelector().text(label));
return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
}
public void openRoot(String label) throws UiObjectNotFoundException {
findRoot(label).click();
mDevice.waitForIdle();
}
public void assertHasRoots(String... labels) throws UiObjectNotFoundException {
List<String> missing = new ArrayList<>();
for (String label : labels) {
if (!findRoot(label).exists()) {
missing.add(label);
}
}
if (!missing.isEmpty()) {
Assert.fail(
"Expected roots " + Arrays.asList(labels) + ", but missing " + missing);
}
}
public void assertHasFocus() {
assertHasFocus(ROOTS_LIST_ID);
}
}

View File

@@ -0,0 +1,219 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.documentsui.bots;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import android.content.Context;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import com.android.documentsui.R;
import java.util.Iterator;
import java.util.List;
/**
* A test helper class that provides support for controlling DocumentsUI activities
* programmatically, and making assertions against the state of the UI.
*
* <p>Support for working directly with Roots and Directory view can be found
* in the respective bots.
*/
public class UiBot extends BaseBot {
public static final String TARGET_PKG = "com.android.documentsui";
private static final String LAUNCHER_PKG = "com.android.launcher";
public UiBot(UiDevice device, Context context, int timeout) {
super(device, context, timeout);
}
public void assertWindowTitle(String expected) {
// Turns out the title field on a window does not have
// an id associated with it at runtime (which confuses the hell out of me)
// In code we address this via "android.R.id.title".
UiObject2 o = find(By.text(expected));
// It's a bit of a conceit that we then *assert* that the title
// is the value that we used to identify the UiObject2.
// If the preceeding lookup fails, this'll choke with an NPE.
// But given the issue described in the comment above, we're
// going to do it anyway. Because we shouldn't be looking up
// the uiobject by it's expected content :|
assertEquals(expected, o.getText());
}
public void assertMenuEnabled(int id, boolean enabled) {
UiObject2 menu= findMenuWithName(mContext.getString(id));
assertNotNull(menu);
assertEquals(enabled, menu.isEnabled());
}
public void assertSearchTextField(boolean isFocused, String query)
throws UiObjectNotFoundException {
UiObject textField = findSearchViewTextField();
UiObject searchIcon = findSearchViewIcon();
assertFalse(searchIcon.exists());
assertTrue(textField.exists());
assertEquals(isFocused, textField.isFocused());
if(query != null) {
assertEquals(query, textField.getText());
}
}
public void assertSearchTextFiledAndIcon(boolean searchTextFieldExists, boolean searchIconExists) {
assertEquals(searchTextFieldExists, findSearchViewTextField().exists());
assertEquals(searchIconExists, findSearchViewIcon().exists());
}
public void openSearchView() throws UiObjectNotFoundException {
UiObject searchView = findSearchView();
searchView.click();
assertTrue(searchView.exists());
}
public void setSearchQuery(String query) throws UiObjectNotFoundException {
UiObject searchView = findSearchView();
assertTrue(searchView.exists());
UiObject searchTextField = findSearchViewTextField();
searchTextField.setText(query);
assertSearchTextField(true, query);
}
public UiObject openOverflowMenu() throws UiObjectNotFoundException {
UiObject obj = findMenuMoreOptions();
obj.click();
mDevice.waitForIdle(mTimeout);
return obj;
}
public void setDialogText(String text) throws UiObjectNotFoundException {
findDialogEditText().setText(text);
}
void switchViewMode() {
UiObject2 mode = menuGridMode();
if (mode != null) {
mode.click();
} else {
menuListMode().click();
}
}
UiObject2 menuGridMode() {
// Note that we're using By.desc rather than By.res, because of b/25285770
return find(By.desc("Grid view"));
}
UiObject2 menuListMode() {
// Note that we're using By.desc rather than By.res, because of b/25285770
return find(By.desc("List view"));
}
public UiObject2 menuDelete() {
return find(By.res("com.android.documentsui:id/menu_delete"));
}
public UiObject2 menuShare() {
return find(By.res("com.android.documentsui:id/menu_share"));
}
public UiObject2 menuRename() {
return findMenuWithName(mContext.getString(R.string.menu_rename));
}
public UiObject2 menuNewFolder() {
return findMenuWithName(mContext.getString(R.string.menu_create_dir));
}
UiObject findSearchView() {
return findObject("com.android.documentsui:id/menu_search");
}
UiObject findSearchViewTextField() {
return findObject("com.android.documentsui:id/menu_search", "android:id/search_src_text");
}
UiObject findSearchViewIcon() {
return findObject("com.android.documentsui:id/menu_search", "android:id/search_button");
}
UiObject findActionModeBar() {
return findObject("android:id/action_mode_bar");
}
public UiObject findDialogEditText() {
return findObject("android:id/content", "android:id/text1");
}
public UiObject findRenameDialogOkButton() {
return findObject("android:id/content", "android:id/button1");
}
public UiObject findRenameDialogCancelButton() {
return findObject("android:id/content", "android:id/button2");
}
UiObject findMenuLabelWithName(String label) {
UiSelector selector = new UiSelector().text(label);
return mDevice.findObject(selector);
}
UiObject2 findMenuWithName(String label) {
List<UiObject2> menuItems = mDevice.findObjects(By.clazz("android.widget.LinearLayout"));
Iterator<UiObject2> it = menuItems.iterator();
UiObject2 menuItem = null;
while(it.hasNext()) {
menuItem = it.next();
UiObject2 text = menuItem.findObject(By.text(label));
if(text != null) {
break;
}
}
return menuItem;
}
UiObject findMenuMoreOptions() {
UiSelector selector = new UiSelector().className("android.widget.ImageButton")
.descriptionContains("More options");
//TODO: use the system string ? android.R.string.action_menu_overflow_description
return mDevice.findObject(selector);
}
public void revealLauncher() {
mDevice.pressHome();
mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), mTimeout);
}
public void revealApp() {
mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), mTimeout);
mDevice.waitForIdle();
}
public void pressKey(int keyCode) {
mDevice.pressKeyCode(keyCode);
}
}