/*
 * Copyright (C) 2014 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.cts.documentclient;

import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.SystemClock;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Path;
import android.provider.DocumentsProvider;
import android.provider.Settings;
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.test.MoreAsserts;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.cts.documentclient.MyActivity.Result;

import java.io.File;
import java.util.List;

/**
 * Tests for {@link DocumentsProvider} and interaction with platform intents
 * like {@link Intent#ACTION_OPEN_DOCUMENT}.
 */
public class DocumentsClientTest extends DocumentsClientTestCase {
    private static final String TAG = "DocumentsClientTest";
    private static final String DOWNLOAD_PATH =
            Environment.getExternalStorageDirectory().getAbsolutePath() + File.separatorChar
                    + Environment.DIRECTORY_DOWNLOADS;
    private static final String TEST_DESTINATION_DIRECTORY_NAME = "TEST_PERMISSION_DESTINATION";
    private static final String TEST_DESTINATION_DIRECTORY_PATH =
            DOWNLOAD_PATH + File.separatorChar + TEST_DESTINATION_DIRECTORY_NAME;
    private static final String TEST_SOURCE_DIRECTORY_NAME = "TEST_PERMISSION_SOURCE";
    private static final String TEST_SOURCE_DIRECTORY_PATH =
            DOWNLOAD_PATH + File.separatorChar + TEST_SOURCE_DIRECTORY_NAME;
    private static final String TEST_TARGET_DIRECTORY_NAME = "TEST_TARGET";
    private static final String TEST_TARGET_DIRECTORY_PATH =
            TEST_SOURCE_DIRECTORY_PATH + File.separatorChar + TEST_TARGET_DIRECTORY_NAME;
    private static final String STORAGE_AUTHORITY = "com.android.externalstorage.documents";

    private UiSelector findRootListSelector() throws UiObjectNotFoundException {
        return new UiSelector().resourceId(
                getDocumentsUiPackageId() + ":id/container_roots").childSelector(
                new UiSelector().resourceId(getDocumentsUiPackageId() + ":id/roots_list"));

    }

    private void revealRoot(UiSelector rootsList, String label) throws UiObjectNotFoundException {
        // We might need to expand drawer if not visible
        if (!new UiObject(rootsList).waitForExists(TIMEOUT)) {
            Log.d(TAG, "Failed to find roots list; trying to expand");
            final UiSelector hamburger = new UiSelector().resourceId(
                    getDocumentsUiPackageId() + ":id/toolbar").childSelector(
                    new UiSelector().className("android.widget.ImageButton").clickable(true));
            new UiObject(hamburger).click();
        }

        // Wait for the first list item to appear
        assertTrue("First list item",
                new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(TIMEOUT));

        // Now scroll around to find our item
        new UiScrollable(rootsList).scrollIntoView(new UiSelector().text(label));
    }

    private UiObject findSearchViewTextField() {
        final UiSelector selector = new UiSelector().resourceId(
                getDocumentsUiPackageId() + ":id/option_menu_search").childSelector(
                new UiSelector().resourceId(getDocumentsUiPackageId() + ":id/search_src_text"));
        return mDevice.findObject(selector);
    }

    private UiObject findRoot(String label) throws UiObjectNotFoundException {
        final UiSelector rootsList = findRootListSelector();
        revealRoot(rootsList, label);

        return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
    }

    private UiObject findActionIcon(String rootLabel) throws UiObjectNotFoundException {
        final UiSelector rootsList = findRootListSelector();
        revealRoot(rootsList, rootLabel);

        final UiScrollable rootsListObject = new UiScrollable(rootsList);
        final UiObject rootItem = rootsListObject.getChildByText(
                new UiSelector().className("android.widget.LinearLayout"), rootLabel, false);
        final UiSelector actionIcon =
                new UiSelector().resourceId(getDocumentsUiPackageId() + ":id/action_icon_area");
        return new UiObject(rootItem.getSelector().childSelector(actionIcon));
    }

    private UiObject findDocument(String label) throws UiObjectNotFoundException {
        final UiSelector docList = new UiSelector().resourceId(getDocumentsUiPackageId() + ":id/dir_list");

        // Wait for the first list item to appear
        assertTrue("First list item",
                new UiObject(docList.childSelector(new UiSelector())).waitForExists(TIMEOUT));

        try {
            //Enfornce to set the list mode
            //Because UiScrollable can't reach the real bottom (when WEB_LINKABLE_FILE item) in grid mode when screen landscape mode
            new UiObject(new UiSelector().resourceId(getDocumentsUiPackageId() + ":id/sub_menu_list")).click();
            mDevice.waitForIdle();
        }catch (UiObjectNotFoundException e){
            //do nothing, already be in list mode.
        }

        // Repeat swipe gesture to find our item
        // (UiScrollable#scrollIntoView does not seem to work well with SwipeRefreshLayout)
        UiObject targetObject = new UiObject(docList.childSelector(new UiSelector().text(label)));
        UiObject saveButton = findSaveButton();
        int stepLimit = 10;
        while (stepLimit-- > 0) {
            if (targetObject.exists()) {
                boolean targetObjectFullyVisible = !saveButton.exists()
                        || targetObject.getVisibleBounds().bottom
                        <= saveButton.getVisibleBounds().top;
                if (targetObjectFullyVisible) {
                    break;
                }
            }

            mDevice.swipe(/* startX= */ mDevice.getDisplayWidth() / 2,
                    /* startY= */ mDevice.getDisplayHeight() / 2,
                    /* endX= */ mDevice.getDisplayWidth() / 2,
                    /* endY= */ 0,
                    /* steps= */ 40);
        }
        return targetObject;
    }

    private UiObject findSaveButton() throws UiObjectNotFoundException {
        return new UiObject(new UiSelector().resourceId(
                getDocumentsUiPackageId() + ":id/container_save")
                .childSelector(new UiSelector().resourceId("android:id/button1")));
    }

    private UiObject findPositiveButton() throws UiObjectNotFoundException {
        return new UiObject(new UiSelector().resourceId("android:id/button1"));
    }

    private void assertToolbarTitleEquals(String label) throws UiObjectNotFoundException {
        final UiObject title = new UiObject(new UiSelector().resourceId(
                getDocumentsUiPackageId() + ":id/toolbar").childSelector(
                new UiSelector().className("android.widget.TextView").text(label)));

        assertTrue(title.waitForExists(TIMEOUT));
    }

    private String getDeviceName() {
        final String deviceName = Settings.Global.getString(
                mActivity.getContentResolver(), Settings.Global.DEVICE_NAME);
        // Device name should always be set. In case it isn't, fall back to "Internal Storage"
        return !TextUtils.isEmpty(deviceName) ? deviceName : "Internal Storage";
    }

    @Override
    public void setUp() throws Exception {
        super.setUp();
        deleteTestDirectory();
    }

    @Override
    public void tearDown() throws Exception {
        super.tearDown();
        deleteTestDirectory();
    }

    public void testOpenSimple() throws Exception {
        if (!supportedHardware()) return;

        try {
            // Opening without permission should fail
            readFully(Uri.parse("content://com.android.cts.documentprovider/document/doc:file1"));
            fail("Able to read data before opened!");
        } catch (SecurityException expected) {
        }

        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        // Ensure that we see both of our roots
        mDevice.waitForIdle();
        assertTrue("CtsLocal root", findRoot("CtsLocal").exists());
        assertTrue("CtsCreate root", findRoot("CtsCreate").exists());
        assertFalse("CtsGetContent root", findRoot("CtsGetContent").exists());

        // Choose the local root.
        mDevice.waitForIdle();
        findRoot("CtsLocal").click();

        // Try picking a virtual file. Virtual files must not be returned for CATEGORY_OPENABLE
        // though, so the click should be ignored.
        mDevice.waitForIdle();
        findDocument("VIRTUAL_FILE").click();
        mDevice.waitForIdle();

        // Pick a regular file.
        mDevice.waitForIdle();
        findDocument("FILE1").click();

        // Confirm that the returned file is a regular file caused by the second click.
        final Result result = mActivity.getResult();
        final Uri uri = result.data.getData();
        assertEquals("doc:file1", DocumentsContract.getDocumentId(uri));

        // We should now have permission to read/write
        MoreAsserts.assertEquals("fileone".getBytes(), readFully(uri));

        writeFully(uri, "replaced!".getBytes());
        SystemClock.sleep(500);
        MoreAsserts.assertEquals("replaced!".getBytes(), readFully(uri));
    }

    public void testOpenVirtual() throws Exception {
        if (!supportedHardware()) return;

        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.setType("*/*");
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        // Pick a virtual file from the local root.
        mDevice.waitForIdle();
        findRoot("CtsLocal").click();

        mDevice.waitForIdle();
        findDocument("VIRTUAL_FILE").click();

        // Confirm that the returned file is actually the selected one.
        final Result result = mActivity.getResult();
        final Uri uri = result.data.getData();
        assertEquals("doc:virtual-file", DocumentsContract.getDocumentId(uri));

        final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
        final String streamTypes[] = resolver.getStreamTypes(uri, "*/*");
        assertEquals(1, streamTypes.length);
        assertEquals("text/plain", streamTypes[0]);

        // Virtual files are not readable unless an alternative MIME type is specified.
        try {
            readFully(uri);
            fail("Unexpected success in reading a virtual file. It should've failed.");
        } catch (IllegalArgumentException e) {
            // Expected.
        }

        // However, they are readable using an alternative MIME type from getStreamTypes().
        MoreAsserts.assertEquals(
                "Converted contents.".getBytes(), readTypedFully(uri, streamTypes[0]));
    }

    public void testCreateNew() throws Exception {
        if (!supportedHardware()) return;

        final String DISPLAY_NAME = "My New Awesome Document Title";
        final String MIME_TYPE = "image/png";

        final Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.putExtra(Intent.EXTRA_TITLE, DISPLAY_NAME);
        intent.setType(MIME_TYPE);
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        mDevice.waitForIdle();
        findRoot("CtsCreate").click();

        mDevice.waitForIdle();
        findSaveButton().click();

        final Result result = mActivity.getResult();
        final Uri uri = result.data.getData();

        writeFully(uri, "meow!".getBytes());

        assertEquals(DISPLAY_NAME, getColumn(uri, Document.COLUMN_DISPLAY_NAME));
        assertEquals(MIME_TYPE, getColumn(uri, Document.COLUMN_MIME_TYPE));
    }

    public void testCreateExisting() throws Exception {
        if (!supportedHardware()) return;

        final Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.putExtra(Intent.EXTRA_TITLE, "NEVERUSED");
        intent.setType("mime2/file2");
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        mDevice.waitForIdle();
        findRoot("CtsCreate").click();

        // Pick file2, which should be selected since MIME matches, then try
        // picking a non-matching MIME, which should leave file2 selected.
        mDevice.waitForIdle();
        findDocument("FILE2").click();
        mDevice.waitForIdle();
        findDocument("FILE1").click();

        mDevice.waitForIdle();
        findSaveButton().click();

        mDevice.waitForIdle();
        findPositiveButton().click();

        final Result result = mActivity.getResult();
        final Uri uri = result.data.getData();

        MoreAsserts.assertEquals("filetwo".getBytes(), readFully(uri));
    }

    public void testTree() throws Exception {
        if (!supportedHardware()) return;

        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        mDevice.waitForIdle();
        findRoot("CtsCreate").click();

        mDevice.waitForIdle();
        findDocument("DIR2").click();
        mDevice.waitForIdle();
        findSaveButton().click();
        mDevice.waitForIdle();
        findPositiveButton().click();

        final Result result = mActivity.getResult();
        final Uri uri = result.data.getData();

        // We should have selected DIR2
        Uri doc = DocumentsContract.buildDocumentUriUsingTree(uri,
                DocumentsContract.getTreeDocumentId(uri));
        Uri children = DocumentsContract.buildChildDocumentsUriUsingTree(uri,
                DocumentsContract.getTreeDocumentId(uri));

        assertEquals("DIR2", getColumn(doc, Document.COLUMN_DISPLAY_NAME));

        // Look around and make sure we can see children
        final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
        Cursor cursor = resolver.query(children, new String[] {
                Document.COLUMN_DISPLAY_NAME }, null, null, null);
        try {
            assertEquals(2, cursor.getCount());
            assertTrue(cursor.moveToFirst());
            assertEquals("FILE4", cursor.getString(0));
        } finally {
            cursor.close();
        }

        // Create some documents
        Uri pic = DocumentsContract.createDocument(resolver, doc, "image/png", "pic.png");
        Uri dir = DocumentsContract.createDocument(resolver, doc, Document.MIME_TYPE_DIR, "my dir");
        Uri dirPic = DocumentsContract.createDocument(resolver, dir, "image/png", "pic2.png");

        writeFully(pic, "pic".getBytes());
        writeFully(dirPic, "dirPic".getBytes());

        // Read then delete existing doc
        final Uri file4 = DocumentsContract.buildDocumentUriUsingTree(uri, "doc:file4");
        MoreAsserts.assertEquals("filefour".getBytes(), readFully(file4));
        assertTrue("delete", DocumentsContract.deleteDocument(resolver, file4));
        try {
            MoreAsserts.assertEquals("filefour".getBytes(), readFully(file4));
            fail("Expected file to be gone");
        } catch (SecurityException expected) {
        }

        // And rename something
        dirPic = DocumentsContract.renameDocument(resolver, dirPic, "wow");
        assertNotNull("rename", dirPic);

        // We should only see single child
        assertEquals("wow", getColumn(dirPic, Document.COLUMN_DISPLAY_NAME));
        MoreAsserts.assertEquals("dirPic".getBytes(), readFully(dirPic));

        try {
            // Make sure we can't see files outside selected dir
            getColumn(DocumentsContract.buildDocumentUriUsingTree(uri, "doc:file1"),
                    Document.COLUMN_DISPLAY_NAME);
            fail("Somehow read document outside tree!");
        } catch (SecurityException expected) {
        }
    }

    public void testRestrictStorageAccessFrameworkEnabled_blockFromTree() throws Exception {
        if (!supportedHardware()) return;

        // Clear DocsUI's storage to avoid it opening stored last location.
        clearDocumentsUi();

        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        mDevice.waitForIdle();

        // save button is disabled for the storage root
        assertFalse(findSaveButton().isEnabled());

        // We should always have Android directory available
        findDocument("Android").click();
        mDevice.waitForIdle();

        // save button is disabled for Android folder
        assertFalse(findSaveButton().isEnabled());

        findRoot(getDeviceName()).click();
        mDevice.waitForIdle();

        try {
            findDocument("Download").click();
            mDevice.waitForIdle();

            // save button is disabled for Download folder
            assertFalse(findSaveButton().isEnabled());
        } catch(UiObjectNotFoundException e) {
            // It might be possible that Download directory does not exist.
        }

        findRoot("CtsCreate").click();
        mDevice.waitForIdle();

        // save button is disabled for CtsCreate root
        assertFalse(findSaveButton().isEnabled());

        findDocument("DIR2").click();

        mDevice.waitForIdle();
        // save button is enabled for dir2
        assertTrue(findSaveButton().isEnabled());
    }

    public void testRestrictStorageAccessFrameworkDisabled_notBlockFromTree() throws Exception {
        if (!supportedHardware())
            return;

        // Clear DocsUI's storage to avoid it opening stored last location.
        clearDocumentsUi();

        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        mDevice.waitForIdle();

        // save button is enabled for for the storage root
        assertTrue(findSaveButton().isEnabled());

        // We should always have Android directory available
        findDocument("Android").click();
        mDevice.waitForIdle();

        // save button is enabled for Android folder
        assertTrue(findSaveButton().isEnabled());

        findRoot(getDeviceName()).click();
        mDevice.waitForIdle();

        try {
            findDocument("Download").click();
            mDevice.waitForIdle();

            // save button is enabled for Download folder
            assertTrue(findSaveButton().isEnabled());
        } catch (UiObjectNotFoundException e) {
            // It might be possible that Download directory does not exist.
        }

        findRoot("CtsCreate").click();
        mDevice.waitForIdle();

        // save button is enabled for CtsCreate root
        assertTrue(findSaveButton().isEnabled());

        findDocument("DIR2").click();

        mDevice.waitForIdle();
        // save button is enabled for dir2
        assertTrue(findSaveButton().isEnabled());
    }

    public void testGetContent_rootsShowing() throws Exception {
        if (!supportedHardware()) return;

        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        // Look around, we should be able to see both DocumentsProviders and
        // other GET_CONTENT sources.
        mDevice.waitForIdle();
        assertTrue("CtsLocal root", findRoot("CtsLocal").exists());
        assertTrue("CtsCreate root", findRoot("CtsCreate").exists());

        // Find and click GetContent item.
        UiObject getContentRoot = findRoot("CtsGetContent");
        mDevice.waitForIdle();
        if (getContentRoot.exists()) {
            // Case 1: GetContent is presented as an independent root item.
            findRoot("CtsGetContent").click();
        } else {
            // Case 2: GetContent is presented as an action icon next to the DocumentsProvider root
            // from the same package.
            // In this case, both CtsLocal and CtsLocal have action icon and have the same action.
            findActionIcon("CtsCreate");
            findActionIcon("CtsLocal").click();
        }

        Result result = mActivity.getResult();
        assertEquals("ReSuLt", result.data.getAction());
    }

    public void testGetContentWithQuery_matchingFileShowing() throws Exception {
        if (!supportedHardware()) return;

        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        final String queryString = "FILE2";
        intent.putExtra(Intent.EXTRA_CONTENT_QUERY, queryString);
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        mDevice.waitForIdle();

        UiObject textField = findSearchViewTextField();
        int tryLimit = 3;

        textField.waitForExists(TIMEOUT);
        assertTrue(textField.exists());

        while (tryLimit-- > 0) {
            if (queryString.equals(textField.getText())) {
                // start search, hide IME
                mDevice.pressEnter();
                break;
            } else {
                SystemClock.sleep(500);
            }
        }

        assertEquals(queryString, textField.getText());

        assertTrue(findDocument(queryString).exists());
    }

    public void testGetContent_returnsResultToCallingActivity() throws Exception {
        if (!supportedHardware()) return;

        final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        mDevice.waitForIdle();
        findRoot("CtsCreate").click();

        // Pick the file.
        mDevice.waitForIdle();
        findDocument("FILE2").click();

        // Confirm that the returned file is a regular file caused by the click.
        final Result result = mActivity.getResult();
        final Uri uri = result.data.getData();
        assertEquals("doc:file2", DocumentsContract.getDocumentId(uri));

        // We should now have permission to read
        MoreAsserts.assertEquals("filetwo".getBytes(), readFully(uri));
    }

    public void testTransferDocument() throws Exception {
        if (!supportedHardware()) return;

        try {
            // Opening without permission should fail.
            readFully(Uri.parse("content://com.android.cts.documentprovider/document/doc:file1"));
            fail("Able to read data before opened!");
        } catch (SecurityException expected) {
        }

        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        mDevice.waitForIdle();
        findRoot("CtsCreate").click();

        findDocument("DIR2").click();
        mDevice.waitForIdle();
        findSaveButton().click();
        mDevice.waitForIdle();
        findPositiveButton().click();

        final Result result = mActivity.getResult();
        final Uri uri = result.data.getData();

        // We should have selected DIR2.
        final Uri docUri = DocumentsContract.buildDocumentUriUsingTree(uri,
                DocumentsContract.getTreeDocumentId(uri));

        assertEquals("DIR2", getColumn(docUri, Document.COLUMN_DISPLAY_NAME));

        final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
        final Cursor cursor = resolver.query(
                DocumentsContract.buildChildDocumentsUriUsingTree(
                        docUri, DocumentsContract.getDocumentId(docUri)),
                new String[] { Document.COLUMN_DOCUMENT_ID, Document.COLUMN_DISPLAY_NAME,
                        Document.COLUMN_FLAGS },
                null, null, null);

        Uri sourceFileUri = null;
        Uri targetDirUri = null;

        try {
            assertEquals(2, cursor.getCount());
            assertTrue(cursor.moveToFirst());
            sourceFileUri = DocumentsContract.buildDocumentUriUsingTree(
                    docUri, cursor.getString(0));
            assertEquals("FILE4", cursor.getString(1));
            assertEquals(Document.FLAG_SUPPORTS_WRITE |
                    Document.FLAG_SUPPORTS_COPY |
                    Document.FLAG_SUPPORTS_MOVE |
                    Document.FLAG_SUPPORTS_REMOVE, cursor.getInt(2));

            assertTrue(cursor.moveToNext());
            targetDirUri = DocumentsContract.buildDocumentUriUsingTree(
                    docUri, cursor.getString(0));
            assertEquals("SUB_DIR2", cursor.getString(1));
        } finally {
            cursor.close();
        }

        // Move, copy then remove.
        final Uri movedFileUri = DocumentsContract.moveDocument(
                resolver, sourceFileUri, docUri, targetDirUri);
        assertTrue(movedFileUri != null);
        final Uri copiedFileUri = DocumentsContract.copyDocument(
                resolver, movedFileUri, targetDirUri);
        assertTrue(copiedFileUri != null);

        // Confirm that the files are at the destinations.
        Cursor cursorDst = resolver.query(
                DocumentsContract.buildChildDocumentsUriUsingTree(
                        targetDirUri, DocumentsContract.getDocumentId(targetDirUri)),
                new String[] { Document.COLUMN_DOCUMENT_ID },
                null, null, null);
        try {
            assertEquals(2, cursorDst.getCount());
            assertTrue(cursorDst.moveToFirst());
            assertEquals("doc:file4", cursorDst.getString(0));
            assertTrue(cursorDst.moveToNext());
            assertEquals("doc:file4_copy", cursorDst.getString(0));
        } finally {
            cursorDst.close();
        }

        // ... and gone from the source.
        final Cursor cursorSrc = resolver.query(
                DocumentsContract.buildChildDocumentsUriUsingTree(
                        docUri, DocumentsContract.getDocumentId(docUri)),
                new String[] { Document.COLUMN_DOCUMENT_ID },
                null, null, null);
        try {
            assertEquals(1, cursorSrc.getCount());
            assertTrue(cursorSrc.moveToFirst());
            assertEquals("doc:sub_dir2", cursorSrc.getString(0));
        } finally {
            cursorSrc.close();
        }

        assertTrue(DocumentsContract.removeDocument(resolver, movedFileUri, targetDirUri));
        assertTrue(DocumentsContract.removeDocument(resolver, copiedFileUri, targetDirUri));

        // Finally, confirm that removing actually removed the files from the destination.
        cursorDst = resolver.query(
                DocumentsContract.buildChildDocumentsUriUsingTree(
                        targetDirUri, DocumentsContract.getDocumentId(targetDirUri)),
                new String[] { Document.COLUMN_DOCUMENT_ID },
                null, null, null);
        try {
            assertEquals(0, cursorDst.getCount());
        } finally {
            cursorDst.close();
        }
    }

    public void testFindDocumentPathInScopedAccess() throws Exception {
        if (!supportedHardware()) return;

        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        mDevice.waitForIdle();
        findRoot("CtsCreate").click();

        mDevice.waitForIdle();
        findDocument("DIR2").click();
        mDevice.waitForIdle();
        findSaveButton().click();
        mDevice.waitForIdle();
        findPositiveButton().click();

        final Result result = mActivity.getResult();
        final Uri uri = result.data.getData();

        // We should have selected DIR2
        Uri doc = DocumentsContract.buildDocumentUriUsingTree(uri,
                DocumentsContract.getTreeDocumentId(uri));

        assertEquals("DIR2", getColumn(doc, Document.COLUMN_DISPLAY_NAME));

        final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();

        // Create some documents
        Uri dir = DocumentsContract.createDocument(resolver, doc, Document.MIME_TYPE_DIR, "my dir");
        Uri dirPic = DocumentsContract.createDocument(resolver, dir, "image/png", "pic2.png");

        writeFully(dirPic, "dirPic".getBytes());

        // Find the path of a document
        Path path = DocumentsContract.findDocumentPath(resolver, dirPic);
        assertNull(path.getRootId());

        final List<String> docs = path.getPath();
        assertEquals("Unexpected path: " + path, 3, docs.size());
        assertEquals(DocumentsContract.getTreeDocumentId(uri), docs.get(0));
        assertEquals(DocumentsContract.getDocumentId(dir), docs.get(1));
        assertEquals(DocumentsContract.getDocumentId(dirPic), docs.get(2));
    }

    public void testOpenDocumentAtInitialLocation() throws Exception {
        if (!supportedHardware()) return;

        // Clear DocsUI's storage to avoid it opening stored last location.
        clearDocumentsUi();

        final Uri docUri = DocumentsContract.buildDocumentUri(PROVIDER_PACKAGE, "doc:file1");
        final Intent intent = new Intent();
        intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("*/*");
        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, docUri);
        mActivity.startActivityForResult(intent, REQUEST_CODE);
        mDevice.waitForIdle();

        assertTrue(findDocument("FILE1").exists());
    }

    public void testOpenDocumentTreeAtInitialLocation() throws Exception {
        if (!supportedHardware()) return;

        // Clear DocsUI's storage to avoid it opening stored last location.
        clearDocumentsUi();

        final Uri docUri = DocumentsContract.buildDocumentUri(PROVIDER_PACKAGE, "doc:dir2");
        final Intent intent = new Intent();
        intent.setAction(Intent.ACTION_OPEN_DOCUMENT_TREE);
        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, docUri);
        mActivity.startActivityForResult(intent, REQUEST_CODE);
        mDevice.waitForIdle();

        assertTrue(findDocument("FILE4").exists());
    }

    public void testOpenDocumentTreeWithScopedStorage() throws Exception {
        if (!supportedHardware()) return;

        // Clear DocsUI's storage to avoid it opening stored last location.
        clearDocumentsUi();

        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
        mActivity.startActivityForResult(intent, REQUEST_CODE);
        mDevice.waitForIdle();

        // assert the default root is internal storage root
        assertToolbarTitleEquals(getDeviceName());

        // no Downloads root
        assertFalse(findRoot("Downloads").exists());
    }

    public void testOpenRootWithoutRootIdAtInitialLocation() throws Exception {
        if (!supportedHardware()) return;

        // Clear DocsUI's storage to avoid it opening stored last location.
        clearDocumentsUi();

        final Uri rootsUri = DocumentsContract.buildRootsUri(PROVIDER_PACKAGE);
        final Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setPackage(getDocumentsUiPackageId());
        intent.setDataAndType(rootsUri, "vnd.android.document/root");
        mActivity.startActivity(intent);
        mDevice.waitForIdle();

        assertTrue(findDocument("DIR1").exists());
    }

    public void testCreateDocumentAtInitialLocation() throws Exception {
        if (!supportedHardware()) return;

        // Clear DocsUI's storage to avoid it opening stored last location.
        clearDocumentsUi();

        final Uri treeUri = DocumentsContract.buildTreeDocumentUri(PROVIDER_PACKAGE, "doc:local");
        final Uri docUri = DocumentsContract.buildDocumentUriUsingTree(treeUri, "doc:file1");
        final Intent intent = new Intent();
        intent.setAction(Intent.ACTION_CREATE_DOCUMENT);
        intent.setType("plain/text");
        intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, docUri);
        mActivity.startActivityForResult(intent, REQUEST_CODE);
        mDevice.waitForIdle();

        assertTrue(findDocument("FILE1").exists());
    }

    public void testCreateWebLink() throws Exception {
        if (!supportedHardware()) return;

        final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.setType("*/*");
        mActivity.startActivityForResult(intent, REQUEST_CODE);

        // Pick a virtual file from the local root.
        mDevice.waitForIdle();
        findRoot("CtsLocal").click();

        mDevice.waitForIdle();
        findDocument("WEB_LINKABLE_FILE").click();

        // Confirm that the returned file is actually the selected one.
        final Result result = mActivity.getResult();
        final Uri uri = result.data.getData();
        assertEquals("doc:web-linkable-file", DocumentsContract.getDocumentId(uri));

        final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();

        Bundle bundle = new Bundle();
        bundle.putStringArray(Intent.EXTRA_EMAIL, new String[] { "x@x.com" });
        final IntentSender intentSender = DocumentsContract.createWebLinkIntent(resolver,
                uri, bundle);

        final int WEB_LINK_REQUEST_CODE = 1;
        mActivity.startIntentSenderForResult(intentSender, WEB_LINK_REQUEST_CODE,
                null, 0, 0, 0);
        mDevice.waitForIdle();

        // Confirm the permissions dialog. The dialog is provided by the stub
        // provider.
        UiObject okButton = new UiObject(new UiSelector().resourceId("android:id/button1"));
        assertNotNull(okButton);
        assertTrue(okButton.waitForExists(TIMEOUT));
        okButton.click();

        final Result webLinkResult = mActivity.getResult();
        assertEquals(WEB_LINK_REQUEST_CODE, webLinkResult.requestCode);
        assertEquals(Activity.RESULT_OK, webLinkResult.resultCode);

        final Uri webLinkUri = webLinkResult.data.getData();
        assertEquals("http://www.foobar.com/shared/SW33TCH3RR13S", webLinkUri.toString());
    }

    public void testEject() throws Exception {
        if (!supportedHardware()) return;

        final Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        intent.setDataAndType(
                DocumentsContract.buildChildDocumentsUri(PROVIDER_PACKAGE, "doc:dir1"),
                Document.MIME_TYPE_DIR);
        mActivity.startActivity(intent);

        findActionIcon("eject").click();

        try {
            findRoot("eject").click();
            fail("Root eject was not ejected");
        } catch(UiObjectNotFoundException e) {
            // expected
        }
    }

    public void testAfterMoveDocumentInStorage_revokeUriPermission() throws Exception {
        if (!supportedHardware()) return;

        final Context context = getInstrumentation().getContext();
        final Uri initUri = DocumentsContract.buildDocumentUri(STORAGE_AUTHORITY,
                "primary:" + Environment.DIRECTORY_DOWNLOADS);

        // create the source directory
        final Uri sourceUri = assertCreateDocumentSuccess(initUri, TEST_SOURCE_DIRECTORY_NAME,
                Document.MIME_TYPE_DIR);

        // create the target directory
        final Uri targetUri = assertCreateDocumentSuccess(sourceUri, TEST_TARGET_DIRECTORY_NAME,
                Document.MIME_TYPE_DIR);
        final int permissionFlag = FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION;

        // check permission for the target uri
        assertEquals(PackageManager.PERMISSION_GRANTED,
                context.checkCallingOrSelfUriPermission(targetUri, permissionFlag));

        // create the destination directory
        final Uri destinationUri = assertCreateDocumentSuccess(initUri,
                TEST_DESTINATION_DIRECTORY_NAME, Document.MIME_TYPE_DIR);

        final ContentResolver resolver = context.getContentResolver();
        final Uri movedFileUri = DocumentsContract.moveDocument(resolver, targetUri, sourceUri,
                destinationUri);
        assertTrue(movedFileUri != null);

        // after moving the document,  the permission of targetUri is revoked
        assertEquals(PackageManager.PERMISSION_DENIED,
                context.checkCallingOrSelfUriPermission(targetUri, permissionFlag));

        // create the target directory again, it still has no permission for targetUri
        executeShellCommand("mkdir " + TEST_TARGET_DIRECTORY_PATH);

        assertEquals(PackageManager.PERMISSION_DENIED,
                context.checkCallingOrSelfUriPermission(targetUri, permissionFlag));
    }

    private Uri assertCreateDocumentSuccess(@Nullable Uri initUri, @NonNull String displayName,
            @NonNull String mimeType) throws Exception {
        // Clear DocsUI's storage to avoid it opening stored last location.
        clearDocumentsUi();

        // create document
        final Intent createIntent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
        createIntent.addCategory(Intent.CATEGORY_OPENABLE);
        createIntent.putExtra(Intent.EXTRA_TITLE, displayName);
        createIntent.setType(mimeType);
        if (initUri != null) {
            createIntent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, initUri);
        }
        mActivity.startActivityForResult(createIntent, REQUEST_CODE);

        mDevice.waitForIdle();
        findSaveButton().click();

        // check result
        final Uri uri = mActivity.getResult().data.getData();
        assertEquals(displayName, getColumn(uri, Document.COLUMN_DISPLAY_NAME));
        assertEquals(mimeType, getColumn(uri, Document.COLUMN_MIME_TYPE));

        return uri;
    }

    private void deleteTestDirectory() throws Exception{
        executeShellCommand("rm -rf " + TEST_DESTINATION_DIRECTORY_PATH);
        executeShellCommand("rm -rf " + TEST_SOURCE_DIRECTORY_PATH);
    }
}
