diff options
| author | 2016-02-01 18:43:41 +0000 | |
|---|---|---|
| committer | 2016-02-01 18:43:41 +0000 | |
| commit | f5c027460eb5ec9257fe48f17afc6f09f8e9212b (patch) | |
| tree | cae5f9676e093e2a722321e2e32ae63a7dbc78dd | |
| parent | b4ec8aaaba6ee5f564875741217bdfaf53a10d5f (diff) | |
| parent | 0950df196fc5a85910e18510eb8dea2a9f233312 (diff) | |
Merge "Add tests for rename documents feature - Add helper class for the Ui tests. It creates basic test environment. It is intermediate layer between UiBot/DocumentsProviderHelper and UiTest classes. - Refactor SearchView tests - Add renaming support in the test DocumentsProvider - Add renaming tests"
8 files changed, 753 insertions, 275 deletions
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java index 467d97ec6402..5df4dcaf11a7 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DocumentsProviderHelper.java @@ -105,6 +105,19 @@ public class DocumentsProviderHelper { return createDocument(root.documentId, mimeType, name); } + public Uri createDocumentWithFlags(String documentId, String mimeType, String name, int flags) + throws RemoteException { + Bundle in = new Bundle(); + in.putInt(StubProvider.EXTRA_FLAGS, flags); + in.putString(StubProvider.EXTRA_PARENT_ID, documentId); + in.putString(Document.COLUMN_MIME_TYPE, mimeType); + in.putString(Document.COLUMN_DISPLAY_NAME, name); + + Bundle out = mClient.call("createDocumentWithFlags", null, in); + Uri uri = out.getParcelable(DocumentsContract.EXTRA_URI); + return uri; + } + public Uri createFolder(Uri parentUri, String name) { return createDocument(parentUri, Document.MIME_TYPE_DIR, name); } @@ -286,4 +299,5 @@ public class DocumentsProviderHelper { return DocumentsContract.buildDocumentUri(mAuthority, documentId); } + } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java index 737a8b699fe9..0a91427c6ad9 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DownloadsActivityUiTest.java @@ -85,7 +85,7 @@ public class DownloadsActivityUiTest extends InstrumentationTestCase { mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT); mDevice.waitForIdle(); - mBot = new UiBot(mDevice, TIMEOUT); + mBot = new UiBot(mDevice, mContext, TIMEOUT); resetStorage(); // Just in case a test failed and tearDown didn't happen. } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java index f0dbfe97f00c..379300b62b8e 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java @@ -82,7 +82,7 @@ public class FilesActivityUiTest extends InstrumentationTestCase { mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT); mDevice.waitForIdle(); - mBot = new UiBot(mDevice, TIMEOUT); + mBot = new UiBot(mDevice, mContext, TIMEOUT); resetStorage(); // Just incase a test failed and tearDown didn't happen. } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java new file mode 100644 index 000000000000..5c6254f90964 --- /dev/null +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RenameDocumentUiTest.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2016 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 com.android.documentsui.StubProvider.ROOT_0_ID; +import static com.android.documentsui.UiTestEnvironment.TIMEOUT; + +import android.support.test.uiautomator.UiObject; +import android.support.test.uiautomator.UiObjectNotFoundException; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.LargeTest; + +@LargeTest +public class RenameDocumentUiTest extends InstrumentationTestCase { + + private static final String TAG = "RenamDocumentUiTest"; + + private final String newName = "kitties.log"; + + private UiTestEnvironment mHelper; + + @Override + public void setUp() throws Exception { + super.setUp(); + mHelper = new UiTestEnvironment(getInstrumentation()); + mHelper.launch(); + mHelper.initTestFiles(); + mHelper.bot().openRoot(ROOT_0_ID); + } + + public void testRenameEnabled_SingleSelection() throws Exception { + mHelper.bot().selectDocument(UiTestEnvironment.fileName1); + mHelper.bot().openOverflowMenu(); + mHelper.bot().assertMenuEnabled(R.string.menu_rename, true); + + // Dismiss more options window + mHelper.device().pressBack(); + } + + public void testNoRenameSupport_SingleSelection() throws Exception { + mHelper.bot().selectDocument(UiTestEnvironment.fileNameNoRename); + mHelper.bot().openOverflowMenu(); + mHelper.bot().assertMenuEnabled(R.string.menu_rename, false); + + // Dismiss more options window + mHelper.device().pressBack(); + } + + public void testOneHasRenameSupport_MultipleSelection() throws Exception { + mHelper.bot().selectDocument(UiTestEnvironment.fileName1); + mHelper.bot().selectDocument(UiTestEnvironment.fileNameNoRename); + mHelper.bot().openOverflowMenu(); + mHelper.bot().assertMenuEnabled(R.string.menu_rename, false); + + // Dismiss more options window + mHelper.device().pressBack(); + } + + public void testRenameDisabled_MultipleSelection() throws Exception { + mHelper.bot().selectDocument(UiTestEnvironment.fileName1); + mHelper.bot().selectDocument(UiTestEnvironment.fileName2); + mHelper.bot().openOverflowMenu(); + mHelper.bot().assertMenuEnabled(R.string.menu_rename, false); + + // Dismiss more options window + mHelper.device().pressBack(); + } + + public void testRenameFile_OkButton() throws Exception { + mHelper.bot().selectDocument(UiTestEnvironment.fileName1); + mHelper.bot().openOverflowMenu(); + mHelper.bot().openDialog(R.string.menu_rename); + mHelper.bot().setDialogText(newName); + mHelper.bot().dismissKeyboardIfPresent(); + + mHelper.device().waitForIdle(TIMEOUT); + mHelper.bot().findRenameDialogOkButton().click(); + mHelper.device().waitForIdle(TIMEOUT); + + mHelper.bot().assertDocument(UiTestEnvironment.fileName1, false); + mHelper.bot().assertDocument(newName, true); + mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0()); + } + + public void testRenameFile_Enter() throws Exception { + mHelper.bot().selectDocument(UiTestEnvironment.fileName1); + mHelper.bot().openOverflowMenu(); + mHelper.bot().openDialog(R.string.menu_rename); + mHelper.bot().setDialogText(newName); + + pressEnter(); + + mHelper.bot().assertDocument(UiTestEnvironment.fileName1, false); + mHelper.bot().assertDocument(newName, true); + mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0()); + } + + public void testRenameFile_Cancel() throws Exception { + mHelper.bot().selectDocument(UiTestEnvironment.fileName1); + mHelper.bot().openOverflowMenu(); + mHelper.bot().openDialog(R.string.menu_rename); + mHelper.bot().setDialogText(newName); + mHelper.bot().dismissKeyboardIfPresent(); + + mHelper.device().waitForIdle(TIMEOUT); + mHelper.bot().findRenameDialogCancelButton().click(); + mHelper.device().waitForIdle(TIMEOUT); + + mHelper.bot().assertDocument(UiTestEnvironment.fileName1, true); + mHelper.bot().assertDocument(newName, false); + mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0()); + } + + public void testRenameDir() throws Exception { + String oldName = "Dir1"; + String newName = "Dir123"; + + mHelper.bot().selectDocument(oldName); + mHelper.bot().openOverflowMenu(); + mHelper.bot().openDialog(R.string.menu_rename); + mHelper.bot().setDialogText(newName); + + pressEnter(); + + mHelper.bot().assertDocument(oldName, false); + mHelper.bot().assertDocument(newName, true); + mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0()); + } + + public void testRename_NameExists() throws Exception { + // Check that document with the new name exists + mHelper.bot().assertDocument(UiTestEnvironment.fileName2, true); + mHelper.bot().selectDocument(UiTestEnvironment.fileName1); + mHelper.bot().openOverflowMenu(); + mHelper.bot().openDialog(R.string.menu_rename); + mHelper.bot().setDialogText(UiTestEnvironment.fileName2); + + pressEnter(); + + mHelper.bot().assertSnackbar(R.string.rename_error); + mHelper.bot().assertDocument(UiTestEnvironment.fileName1, true); + mHelper.bot().assertDocument(UiTestEnvironment.fileName2, true); + mHelper.bot().assertDocumentsCount(mHelper.getDocumentsCountDir0()); + } + + private void pressEnter() { + mHelper.device().waitForIdle(TIMEOUT); + mHelper.device().pressEnter(); + mHelper.device().waitForIdle(TIMEOUT); + } + +} diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java index 6c9c5d9f8216..ce5472580731 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/SearchViewUiTest.java @@ -16,278 +16,139 @@ package com.android.documentsui; -import static com.android.documentsui.StubProvider.DEFAULT_AUTHORITY; import static com.android.documentsui.StubProvider.ROOT_0_ID; import static com.android.documentsui.StubProvider.ROOT_1_ID; -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.support.test.uiautomator.By; -import android.support.test.uiautomator.Configurator; -import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; -import android.support.test.uiautomator.Until; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; -import android.view.MotionEvent; - -import com.android.documentsui.model.RootInfo; @LargeTest public class SearchViewUiTest extends InstrumentationTestCase { - private static final int TIMEOUT = 5000; private static final String TAG = "SearchViewUiTest"; - private static final String TARGET_PKG = "com.android.documentsui"; - private static final String LAUNCHER_PKG = "com.android.launcher"; - - private UiBot mBot; - private UiDevice mDevice; - private Context mContext; - private ContentResolver mResolver; - private DocumentsProviderHelper mDocsHelper; - private ContentProviderClient mClient; - private RootInfo mRoot_0; - private RootInfo mRoot_1; - - private UiObject mSearchView; - private UiObject mSearchTextField; + + private UiTestEnvironment mEnv; + private UiObject mDocsList; private UiObject mMessageTextView; - private UiObject mSearchIcon; + @Override public void setUp() throws Exception { - // Initialize UiDevice instance. - Instrumentation instrumentation = getInstrumentation(); - - mDevice = UiDevice.getInstance(instrumentation); - - Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE); - - // Start from the home screen. - mDevice.pressHome(); - mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), TIMEOUT); + super.setUp(); + mEnv = new UiTestEnvironment(getInstrumentation()); + mEnv.launch(); - // NOTE: Must be the "target" context, else security checks in content provider will fail. - mContext = instrumentation.getTargetContext(); - mResolver = mContext.getContentResolver(); - - mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY); - mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient); - - // Launch app. - Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(TARGET_PKG); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - mContext.startActivity(intent); - // Wait for the app to appear. - mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT); - mDevice.waitForIdle(); - - mBot = new UiBot(mDevice, TIMEOUT); - - resetStorage(); // Just incase a test failed and tearDown didn't happen. - - initUiObjects(); } @Override protected void tearDown() throws Exception { + mEnv.device().pressBack(); super.tearDown(); - mDevice.pressBack(); - resetStorage(); - mClient.release(); } - private void resetStorage() throws RemoteException { - mClient.call("clear", null, null); - // TODO: Would be nice to have an event to wait on here. - mDevice.waitForIdle(); + public void testSearchView_ExpandsOnClick() throws Exception { + mEnv.bot().openSearchView(); + mEnv.bot().assertSearchTextFiledAndIcon(true, false); } - private void initTestFiles() throws RemoteException { - mRoot_0 = mDocsHelper.getRoot(ROOT_0_ID); - mRoot_1 = mDocsHelper.getRoot(ROOT_1_ID); + public void testSearchView_CollapsesOnBack() throws Exception { + mEnv.bot().openSearchView(); - mDocsHelper.createDocument(mRoot_0, "text/plain", "file10.log"); - mDocsHelper.createDocument(mRoot_0, "image/png", "file1.png"); - mDocsHelper.createDocument(mRoot_0, "text/csv", "file2.csv"); + mEnv.device().pressBack(); - mDocsHelper.createDocument(mRoot_1, "text/plain", "anotherFile0.log"); - mDocsHelper.createDocument(mRoot_1, "text/plain", "poodles.text"); + mEnv.bot().assertSearchTextFiledAndIcon(false, true); } - private void initUiObjects() { - mSearchView = mBot.findSearchView(); - mSearchTextField = mBot.findSearchViewTextField(); - mDocsList = mBot.findDocumentsList(); - mMessageTextView = mBot.findMessageTextView(); - mSearchIcon = mBot.findSearchViewIcon(); - } - - public void testSearchViewExpandsOnClick() throws Exception { - assertTrue(mSearchIcon.exists()); - assertFalse(mSearchTextField.exists()); - - mSearchView.click(); - - assertTrue(mSearchTextField.exists()); - assertTrue(mSearchTextField.isFocused()); - assertFalse(mSearchIcon.exists()); - } - - public void testSearchViewCollapsesOnBack() throws Exception { - assertTrue(mSearchIcon.exists()); - assertFalse(mSearchTextField.exists()); - - mSearchView.click(); - - mDevice.pressBack(); - - assertTrue(mSearchIcon.exists()); - assertFalse(mSearchTextField.exists()); - } - - public void testSearchViewClearsTextOnBack() throws Exception { - assertTrue(mSearchIcon.exists()); - assertFalse(mSearchTextField.exists()); - + public void testSearchView_ClearsTextOnBack() throws Exception { String query = "file2"; - mSearchView.click(); - mSearchTextField.setText(query); - - assertSearchTextField(true, query); + mEnv.bot().openSearchView(); + mEnv.bot().setSearchQuery(query); - mDevice.pressBack(); + mEnv.device().pressBack(); - assertTrue(mSearchIcon.exists()); - assertFalse(mSearchTextField.exists()); + mEnv.bot().assertSearchTextFiledAndIcon(false, true); } - public void testSearchFound() throws Exception { - initTestFiles(); - - mBot.openRoot(ROOT_0_ID); - - assertDefaultTestDir0(); + public void testSearch_ResultsFound() throws Exception { + mEnv.initTestFiles(); + mEnv.bot().openRoot(ROOT_0_ID); + mEnv.assertDefaultContentOfTestDir0(); String query = "file1"; - mSearchView.click(); - mSearchTextField.setText(query); - - assertTrue(mDocsList.exists()); - assertSearchTextField(true, query); + mEnv.bot().openSearchView(); + mEnv.bot().setSearchQuery(query); + mEnv.bot().assertSearchTextField(true, query); - mDevice.pressEnter(); + mEnv.device().pressEnter(); - assertTrue(mDocsList.exists()); - assertEquals(2, mDocsList.getChildCount()); - mBot.assertHasDocuments("file1.png", "file10.log"); - assertSearchTextField(false, query); + mEnv.bot().assertDocumentsCountOnList(true, 2); + mEnv.bot().assertHasDocuments(UiTestEnvironment.fileName1, UiTestEnvironment.fileName2); + mEnv.bot().assertSearchTextField(false, query); } - public void testSearchFoundClearsOnBack() throws Exception { - initTestFiles(); - - mBot.openRoot(ROOT_0_ID); - - assertDefaultTestDir0(); - - String query = "file1"; - mSearchView.click(); - mSearchTextField.setText(query); + public void testSearchResultsFound_ClearsOnBack() throws Exception { + mEnv.initTestFiles(); + mEnv.bot().openRoot(ROOT_0_ID); + mEnv.assertDefaultContentOfTestDir0(); - mDevice.pressEnter(); - mDevice.pressBack(); + String query = UiTestEnvironment.fileName1; + mEnv.bot().openSearchView(); + mEnv.bot().setSearchQuery(query); - assertDefaultTestDir0(); + mEnv.device().pressEnter(); + mEnv.device().pressBack(); + mEnv.assertDefaultContentOfTestDir0(); } - public void testSearchNoResults() throws Exception { - initTestFiles(); - - mBot.openRoot(ROOT_0_ID); - - assertDefaultTestDir0(); + public void testSearch_NoResults() throws Exception { + mEnv.initTestFiles(); + mEnv.bot().openRoot(ROOT_0_ID); + mEnv.assertDefaultContentOfTestDir0(); String query = "chocolate"; - mSearchView.click(); - mSearchTextField.setText(query); + mEnv.bot().openSearchView(); + mEnv.bot().setSearchQuery(query); - mDevice.pressEnter(); + mEnv.device().pressEnter(); - assertFalse(mDocsList.exists()); - assertTrue(mMessageTextView.exists()); - String msg = String.valueOf(mContext.getString(R.string.no_results)); - assertEquals(String.format(msg, "TEST_ROOT_0"), mMessageTextView.getText()); - assertSearchTextField(false, query); - } - - public void testSearchNoResultsClearsOnBack() throws Exception { - initTestFiles(); + mEnv.bot().assertDocumentsCountOnList(false, 0); - mBot.openRoot(ROOT_0_ID); + String msg = String.valueOf(mEnv.context().getString(R.string.no_results)); + mEnv.bot().assertMessageTextView(String.format(msg, "TEST_ROOT_0")); + mEnv.bot().assertSearchTextField(false, query); + } - assertDefaultTestDir0(); + public void testSearchNoResults_ClearsOnBack() throws Exception { + mEnv.initTestFiles(); + mEnv.bot().openRoot(ROOT_0_ID); + mEnv.assertDefaultContentOfTestDir0(); String query = "chocolate"; - mSearchView.click(); - mSearchTextField.setText(query); + mEnv.bot().openSearchView(); + mEnv.bot().setSearchQuery(query); - mDevice.pressEnter(); - mDevice.pressBack(); - - assertDefaultTestDir0(); + mEnv.device().pressEnter(); + mEnv.device().pressBack(); + mEnv.assertDefaultContentOfTestDir0(); } - public void testSearchFoundClearsDirectoryChange() throws Exception { - initTestFiles(); - - mBot.openRoot(ROOT_0_ID); - - assertDefaultTestDir0(); - - String query = "file1"; - mSearchView.click(); - mSearchTextField.setText(query); - - mDevice.pressEnter(); + public void testSearchResultsFound_ClearsOnDirectoryChange() throws Exception { + mEnv.initTestFiles(); + mEnv.bot().openRoot(ROOT_0_ID); + mEnv.assertDefaultContentOfTestDir0(); - mBot.openRoot(ROOT_1_ID); + String query = UiTestEnvironment.fileName1; + mEnv.bot().openSearchView(); + mEnv.bot().setSearchQuery(query); - assertDefaultTestDir1(); + mEnv.device().pressEnter(); - mBot.openRoot(ROOT_0_ID); - - assertDefaultTestDir0(); - } - - private void assertDefaultTestDir0() throws UiObjectNotFoundException { - assertTrue(mSearchIcon.exists()); - assertTrue(mDocsList.exists()); - assertFalse(mSearchTextField.exists()); - assertEquals(3, mDocsList.getChildCount()); - mBot.assertHasDocuments("file2.csv", "file1.png", "file10.log"); - } - - private void assertDefaultTestDir1() throws UiObjectNotFoundException { - assertTrue(mSearchIcon.exists()); - assertFalse(mSearchTextField.exists()); - assertTrue(mDocsList.exists()); - assertEquals(2, mDocsList.getChildCount()); - mBot.assertHasDocuments("anotherFile0.log", "poodles.text"); - } + mEnv.bot().openRoot(ROOT_1_ID); + mEnv.assertDefaultContentOfTestDir1(); - private void assertSearchTextField(boolean isFocused, String query) - throws UiObjectNotFoundException { - assertFalse(mSearchIcon.exists()); - assertTrue(mSearchTextField.exists()); - assertEquals(isFocused, mSearchTextField.isFocused()); - assertEquals(query, mSearchTextField.getText()); + mEnv.bot().openRoot(ROOT_0_ID); + mEnv.assertDefaultContentOfTestDir0(); } } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java index cc487861cf6d..980627b17e7c 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java @@ -16,6 +16,10 @@ package com.android.documentsui; +import static com.android.documentsui.Shared.TAG; + +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ProviderInfo; @@ -34,6 +38,7 @@ import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; import android.support.annotation.VisibleForTesting; +import android.text.TextUtils; import android.util.Log; import libcore.io.IoUtils; @@ -66,10 +71,13 @@ public class StubProvider extends DocumentsProvider { = "com.android.documentsui.stubprovider.STREAM_TYPES"; public static final String EXTRA_CONTENT = "com.android.documentsui.stubprovider.CONTENT"; + public static final String EXTRA_FLAGS = "com.android.documentsui.stubprovider.FLAGS"; + public static final String EXTRA_PARENT_ID = "com.android.documentsui.stubprovider.PARENT"; + private static final String TAG = "StubProvider"; private static final String STORAGE_SIZE_KEY = "documentsui.stubprovider.size"; - private static int DEFAULT_ROOT_SIZE = 1024 * 1024 * 100; // 100 MB. + private static int DEFAULT_ROOT_SIZE = 1024 * 1024 * 100; // 100 MB. private static final String[] DEFAULT_ROOT_PROJECTION = new String[] { Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID, @@ -176,44 +184,8 @@ public class StubProvider extends DocumentsProvider { @Override public String createDocument(String parentId, String mimeType, String displayName) throws FileNotFoundException { - - final StubDocument parent = mStorage.get(parentId); - if (parent == null) { - throw new IllegalArgumentException( - "Can't create file " + displayName + " in null parent."); - } - if (!parent.file.isDirectory()) { - throw new IllegalArgumentException( - "Can't create file " + displayName + " inside non-directory parent " - + parent.file.getName()); - } - - final File file = new File(parent.file, displayName); - if (file.exists()) { - throw new FileNotFoundException( - "Duplicate file names not supported for " + file); - } - - if (mimeType.equals(Document.MIME_TYPE_DIR)) { - if (!file.mkdirs()) { - throw new FileNotFoundException( - "Failed to create directory(s): " + file); - } - Log.i(TAG, "Created new directory: " + file); - } else { - boolean created = false; - try { - created = file.createNewFile(); - } catch (IOException e) { - // We'll throw an FNF exception later :) - Log.e(TAG, "createNewFile operation failed for file: " + file, e); - } - if (!created) { - throw new FileNotFoundException( - "createNewFile operation failed for: " + file); - } - Log.i(TAG, "Created new file: " + file); - } + StubDocument parent = mStorage.get(parentId); + File file = createFile(parent, mimeType, displayName); final StubDocument document = StubDocument.createRegularDocument(file, mimeType, parent); mStorage.put(document.documentId, document); @@ -303,6 +275,45 @@ public class StubProvider extends DocumentsProvider { } @Override + public String renameDocument(String documentId, String displayName) + throws FileNotFoundException { + + StubDocument oldDoc = mStorage.get(documentId); + + File before = oldDoc.file; + File after = new File(before.getParentFile(), displayName); + + if (after.exists()) { + throw new IllegalStateException("Already exists " + after); + } + + boolean result = before.renameTo(after); + + if (!result) { + throw new IllegalStateException("Failed to rename to " + after); + } + + StubDocument newDoc = StubDocument.createRegularDocument(after, oldDoc.mimeType, + mStorage.get(oldDoc.parentId)); + + mStorage.remove(documentId); + notifyParentChanged(oldDoc.parentId); + getContext().getContentResolver().notifyChange( + DocumentsContract.buildDocumentUri(mAuthority, oldDoc.documentId), null, false); + + mStorage.put(newDoc.documentId, newDoc); + notifyParentChanged(newDoc.parentId); + getContext().getContentResolver().notifyChange( + DocumentsContract.buildDocumentUri(mAuthority, newDoc.documentId), null, false); + + if (!TextUtils.equals(documentId, newDoc.documentId)) { + return newDoc.documentId; + } else { + return null; + } + } + + @Override public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal) throws FileNotFoundException { @@ -468,6 +479,9 @@ public class StubProvider extends DocumentsProvider { case "simulateReadErrorsForFile": simulateReadErrorsForFile(arg); return null; + case "createDocumentWithFlags": + Bundle bundle = dispatchCreateDocumentWithFlags(extras); + return bundle; default: return super.call(method, arg, extras); } @@ -493,6 +507,81 @@ public class StubProvider extends DocumentsProvider { return null; } + private Bundle dispatchCreateDocumentWithFlags(Bundle extras) { + String rootId = extras.getString(EXTRA_PARENT_ID); + String mimeType = extras.getString(Document.COLUMN_MIME_TYPE); + String name = extras.getString(Document.COLUMN_DISPLAY_NAME); + int flags = extras.getInt(EXTRA_FLAGS); + + Bundle out = new Bundle(); + String documentId = null; + try { + documentId = createDocument(rootId, mimeType, name, flags); + Uri uri = DocumentsContract.buildDocumentUri(mAuthority, documentId); + out.putParcelable(DocumentsContract.EXTRA_URI, uri); + } catch (FileNotFoundException e) { + Log.d(TAG, "Cretaing document with flags failed" + name); + } + return out; + } + + public String createDocument(String parentId, String mimeType, String displayName, int flags) + throws FileNotFoundException { + + StubDocument parent = mStorage.get(parentId); + File file = createFile(parent, mimeType, displayName); + + final StubDocument document = StubDocument.createDocumentWithFlags(file, mimeType, parent, + flags); + mStorage.put(document.documentId, document); + Log.d(TAG, "Created document " + document.documentId); + notifyParentChanged(document.parentId); + getContext().getContentResolver().notifyChange( + DocumentsContract.buildDocumentUri(mAuthority, document.documentId), + null, false); + + return document.documentId; + } + + private File createFile(StubDocument parent, String mimeType, String displayName) + throws FileNotFoundException { + if (parent == null) { + throw new IllegalArgumentException( + "Can't create file " + displayName + " in null parent."); + } + if (!parent.file.isDirectory()) { + throw new IllegalArgumentException( + "Can't create file " + displayName + " inside non-directory parent " + + parent.file.getName()); + } + + final File file = new File(parent.file, displayName); + if (file.exists()) { + throw new FileNotFoundException( + "Duplicate file names not supported for " + file); + } + + if (mimeType.equals(Document.MIME_TYPE_DIR)) { + if (!file.mkdirs()) { + throw new FileNotFoundException("Failed to create directory(s): " + file); + } + Log.i(TAG, "Created new directory: " + file); + } else { + boolean created = false; + try { + created = file.createNewFile(); + } catch (IOException e) { + // We'll throw an FNF exception later :) + Log.e(TAG, "createNewFile operation failed for file: " + file, e); + } + if (!created) { + throw new FileNotFoundException("createNewFile operation failed for: " + file); + } + Log.i(TAG, "Created new file: " + file); + } + return file; + } + private void configure(String arg, Bundle extras) { Log.d(TAG, "Configure " + arg); String rootName = extras.getString(EXTRA_ROOT, ROOT_0_ID); @@ -557,7 +646,7 @@ public class StubProvider extends DocumentsProvider { } final StubDocument document = StubDocument.createRegularDocument(file, mimeType, parent); mStorage.put(document.documentId, document); - return DocumentsContract.buildDocumentUri(mAuthority, document.documentId); + return DocumentsContract.buildDocumentUri(mAuthority, document.documentId); } @VisibleForTesting @@ -573,7 +662,7 @@ public class StubProvider extends DocumentsProvider { final StubDocument document = StubDocument.createVirtualDocument( file, mimeType, streamTypes, parent); mStorage.put(document.documentId, document); - return DocumentsContract.buildDocumentUri(mAuthority, document.documentId); + return DocumentsContract.buildDocumentUri(mAuthority, document.documentId); } @VisibleForTesting @@ -643,9 +732,8 @@ public class StubProvider extends DocumentsProvider { public final String parentId; public final RootInfo rootInfo; - private StubDocument( - File file, String mimeType, List<String> streamTypes, int flags, - StubDocument parent) { + private StubDocument(File file, String mimeType, List<String> streamTypes, int flags, + StubDocument parent) { this.file = file; this.documentId = getDocumentIdForFile(file); this.mimeType = mimeType; @@ -671,7 +759,7 @@ public class StubProvider extends DocumentsProvider { public static StubDocument createRegularDocument( File file, String mimeType, StubDocument parent) { - int flags = Document.FLAG_SUPPORTS_DELETE; + int flags = Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_RENAME; if (file.isDirectory()) { flags |= Document.FLAG_DIR_SUPPORTS_CREATE; } else { @@ -680,6 +768,11 @@ public class StubProvider extends DocumentsProvider { return new StubDocument(file, mimeType, new ArrayList<String>(), flags, parent); } + public static StubDocument createDocumentWithFlags( + File file, String mimeType, StubDocument parent, int flags) { + return new StubDocument(file, mimeType, new ArrayList<String>(), flags, parent); + } + public static StubDocument createVirtualDocument( File file, String mimeType, List<String> streamTypes, StubDocument parent) { int flags = Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_WRITE diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java index c4def8f600eb..f12ae106bb00 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java @@ -17,7 +17,11 @@ 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.content.Context; import android.support.test.uiautomator.By; import android.support.test.uiautomator.BySelector; import android.support.test.uiautomator.UiDevice; @@ -28,11 +32,13 @@ 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.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; @@ -48,10 +54,12 @@ class UiBot { By.desc(Pattern.compile("^Deleting [0-9]+ file.+")); private UiDevice mDevice; + private Context mContext; private int mTimeout; - public UiBot(UiDevice device, int timeout) { + public UiBot(UiDevice device, Context context, int timeout) { mDevice = device; + mContext = context; mTimeout = timeout; } @@ -109,25 +117,40 @@ class UiBot { } } - 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/list")); + void assertMenuEnabled(int id, boolean enabled) { + UiObject2 menu= findMenuWithName(mContext.getString(id)); + assertNotNull(menu); + assertEquals(enabled, menu.isEnabled()); + } - // Wait for the first list item to appear - new UiObject(docList.childSelector(new UiSelector())).waitForExists(mTimeout); + void assertDocumentsCount(int count) throws UiObjectNotFoundException { + UiObject docsList = findDocumentsList(); + assertEquals(count, docsList.getChildCount()); + } - // new UiScrollable(docList).scrollIntoView(new UiSelector().text(label)); - return mDevice.findObject(docList.childSelector(new UiSelector().text(label))); + void assertDocumentsCount(String dir, int count) throws UiObjectNotFoundException { + openRoot(dir); + UiObject docsList = findDocumentsList(); + assertEquals(count, docsList.getChildCount()); } - boolean hasDocuments(String... labels) throws UiObjectNotFoundException { - for (String label : labels) { - if (!findDocument(label).exists()) { - return false; - } + 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()); } - return true; + } + + void assertSearchTextFiledAndIcon(boolean searchTextFieldExists, boolean searchIconExists) { + assertEquals(searchTextFieldExists, findSearchViewTextField().exists()); + assertEquals(searchIconExists, findSearchViewIcon().exists()); + } void assertHasDocuments(String... labels) throws UiObjectNotFoundException { @@ -143,10 +166,77 @@ class UiBot { } } + 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))); + } + 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); } @@ -200,6 +290,27 @@ class UiBot { 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/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", @@ -224,4 +335,60 @@ class UiBot { "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(); + } + } + } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UiTestEnvironment.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UiTestEnvironment.java new file mode 100644 index 000000000000..9e30589aa973 --- /dev/null +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/UiTestEnvironment.java @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016 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 com.android.documentsui.StubProvider.DEFAULT_AUTHORITY; +import static com.android.documentsui.StubProvider.ROOT_0_ID; +import static com.android.documentsui.StubProvider.ROOT_1_ID; + +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.view.MotionEvent; + +import com.android.documentsui.model.RootInfo; + +/** + * Provides basic test environment for UI tests: + * - Launches activity + * - Creates and gives access to test root directories and test files + * - Cleans up the test environment + */ +class UiTestEnvironment { + + public static final int TIMEOUT = 5000; + public static final String NO_RENAME = "NO_RENAME"; + + public static final String dirName1 = "Dir1"; + public static final String fileName1 = "file1.log"; + public static final String fileName2 = "file12.png"; + public static final String fileName3 = "anotherFile0.log"; + public static final String fileName4 = "poodles.text"; + public static final String fileNameNoRename = NO_RENAME + "file.txt"; + + private static final String TARGET_PKG = "com.android.documentsui"; + private static final String LAUNCHER_PKG = "com.android.launcher"; + + private final UiBot mBot; + private final UiDevice mDevice; + private final Context mContext; + + private RootInfo mRootDir0; + private RootInfo mRootDir1; + private int mDocsCountDir0; + private int mDocsCountDir1; + + private ContentResolver mResolver; + private DocumentsProviderHelper mDocsHelper; + private ContentProviderClient mClient; + + private final Instrumentation mInstrumentation; + + public UiTestEnvironment(Instrumentation instrumentation) { + mInstrumentation = instrumentation; + mDevice = UiDevice.getInstance(mInstrumentation); + // NOTE: Must be the "target" context, else security checks in content provider will fail. + mContext = mInstrumentation.getTargetContext(); + mBot = new UiBot(mDevice, mContext, TIMEOUT); + } + +/** + * Launches default activity and waits for the application to appear. + * @throws Exception + */ + public void launch() throws Exception { + Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(TARGET_PKG); + launch(intent); + } + + /** + * Launches activity specified by intent and waits for the application to appear. + * @param intent Intent describing activity to launch. + * @throws Exception + */ + public void launch(Intent intent) throws Exception { + Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE); + // Start from the home screen. + mDevice.pressHome(); + mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), TIMEOUT); + + mResolver = mContext.getContentResolver(); + mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY); + mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient); + + // Launch app. + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + // Wait for the app to appear. + mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), TIMEOUT); + mDevice.waitForIdle(); + + resetStorage(); // Just incase a test failed and tearDown didn't happen. + } + + public void cleanUp() throws Exception { + resetStorage(); + mClient.release(); + } + + public void resetStorage() throws RemoteException { + mClient.call("clear", null, null); + mDevice.waitForIdle(); + } + + public void initTestFiles() throws RemoteException { + mRootDir0 = mDocsHelper.getRoot(ROOT_0_ID); + mRootDir1 = mDocsHelper.getRoot(ROOT_1_ID); + + mDocsHelper.createFolder(mRootDir0, dirName1); + mDocsHelper.createDocument(mRootDir0, "text/plain", fileName1); + mDocsHelper.createDocument(mRootDir0, "image/png", fileName2); + mDocsHelper.createDocumentWithFlags(mRootDir0.documentId, "text/plain", fileNameNoRename, + Document.FLAG_SUPPORTS_WRITE); + mDocsCountDir0 = 4; + + mDocsHelper.createDocument(mRootDir1, "text/plain", fileName3); + mDocsHelper.createDocument(mRootDir1, "text/plain", fileName4); + mDocsCountDir1 = 2; + } + + public void assertDefaultContentOfTestDir0() throws UiObjectNotFoundException { + bot().assertDocumentsCount(ROOT_0_ID, getDocumentsCountDir0()); + bot().assertHasDocuments(UiTestEnvironment.fileName1, UiTestEnvironment.fileName2, + UiTestEnvironment.dirName1, UiTestEnvironment.fileNameNoRename); + } + + public void assertDefaultContentOfTestDir1() throws UiObjectNotFoundException { + bot().assertDocumentsCount(ROOT_1_ID, getDocumentsCountDir1()); + bot().assertHasDocuments(UiTestEnvironment.fileName3, UiTestEnvironment.fileName4); + } + + public UiBot bot() { + return mBot; + } + + public UiDevice device() { + return mDevice; + } + + public Context context() { + return mContext; + } + + public RootInfo getRootDir0() { + return mRootDir0; + } + + public int getDocumentsCountDir0() { + return mDocsCountDir0; + } + + public int getDocumentsCountDir1() { + return mDocsCountDir1; + } +} |