15fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey/*
25fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * Copyright (C) 2014 The Android Open Source Project
35fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey *
45fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
55fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * you may not use this file except in compliance with the License.
65fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * You may obtain a copy of the License at
75fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey *
85fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
95fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey *
105fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
115fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
125fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * See the License for the specific language governing permissions and
145fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * limitations under the License.
155fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey */
165fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
175fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeypackage android.support.v4.provider;
185fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
195fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.content.ContentResolver;
205fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.content.UriPermission;
215fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.net.Uri;
225fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.os.Environment;
235fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.os.SystemClock;
24754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.test.filters.MediumTest;
255fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport android.test.AndroidTestCase;
260357e3dab075ba93be2af9338f42d9cdb1217016Aurimas Liutikasimport android.test.suitebuilder.annotation.Suppress;
275fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
285fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport java.io.DataInputStream;
295fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport java.io.DataOutputStream;
305fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport java.io.File;
315fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport java.io.FileInputStream;
325fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport java.io.FileOutputStream;
335fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport java.io.IOException;
345fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeyimport java.util.List;
355fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
365fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey/**
375fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey * Tests for {@link DocumentFile}
380357e3dab075ba93be2af9338f42d9cdb1217016Aurimas Liutikas *
395fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey */
400357e3dab075ba93be2af9338f42d9cdb1217016Aurimas Liutikas// These tests fail so it is marked @Suppress. Fix is tracked in b/27168036
410357e3dab075ba93be2af9338f42d9cdb1217016Aurimas Liutikas@Suppress
420357e3dab075ba93be2af9338f42d9cdb1217016Aurimas Liutikas@MediumTest
435fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkeypublic class DocumentFileTest extends AndroidTestCase {
445fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
455fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private Uri treeUri;
465fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
475fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private File root;
485fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private File rootFoo;
495fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private File rootMeow;
505fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private File rootMeowCat;
515fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private File rootMeowDog;
525fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private File rootMeowBar;
535fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
545fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private static final String FOO = "foo.randomext";
555fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private static final String MEOW = "meow";
565fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private static final String CAT = "cat.jpg";
575fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private static final String DOG = "DOG.PDF";
585fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private static final String BAR = "bar.png";
595fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
605fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    @Override
615fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    protected void setUp() throws Exception {
625fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        super.setUp();
635fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
645fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final ContentResolver resolver = getContext().getContentResolver();
655fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final List<UriPermission> perms = resolver.getPersistedUriPermissions();
665fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
675fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        if (perms.isEmpty()) {
685fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            throw new RuntimeException(
695fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                    "Failed to find outstanding grant; did you run the activity first?");
705fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        } else {
715fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            treeUri = perms.get(0).getUri();
725fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        }
735fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
745fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        root = Environment.getExternalStorageDirectory();
755fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        rootFoo = new File(root, FOO);
765fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        rootMeow = new File(root, MEOW);
775fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        rootMeowCat = new File(rootMeow, CAT);
785fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        rootMeowDog = new File(rootMeow, DOG);
795fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        rootMeowBar = new File(rootMeow, BAR);
805fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
815fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        resetRoot();
825fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
835fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
845fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private void resetRoot() throws Exception {
855fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final File tmp = new File(root, "bark.pdf");
86120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette        deleteContents(tmp);
875fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        tmp.delete();
885fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
89120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette        deleteContents(rootMeow);
905fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        rootMeow.mkdir();
915fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        rootMeowBar.mkdir();
925fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
935fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        writeInt(rootFoo, 12);
945fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        writeInt(rootMeowCat, 24);
955fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        writeInt(rootMeowDog, 48);
965fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
975fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
98120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette    public static boolean deleteContents(File dir) {
99120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette        File[] files = dir.listFiles();
100120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette        boolean success = true;
101120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette        if (files != null) {
102120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette            for (File file : files) {
103120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette                if (file.isDirectory()) {
104120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette                    success &= deleteContents(file);
105120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette                }
106120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette                if (!file.delete()) {
107120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette                    success = false;
108120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette                }
109120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette            }
110120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette        }
111120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette        return success;
112120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette    }
113120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette
1145fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private interface DocumentTest {
1155fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        public void exec(DocumentFile doc) throws Exception;
1165fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
1175fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1185fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public void testSimple() throws Exception {
1195fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DocumentTest test = new DocumentTest() {
1205fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            @Override
1215fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            public void exec(DocumentFile doc) throws Exception {
1225fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                resetRoot();
1235fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("isDirectory", doc.isDirectory());
1245fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertFalse("isFile", doc.isFile());
12526f311a9b57b9551ad58d6b7f9a571bebcebf0dcTomasz Mikolajewski                assertFalse("isVirtual", doc.isVirtual());
1265fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("canRead", doc.canRead());
1275fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("canWrite", doc.canWrite());
1285fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("exists", doc.exists());
1295fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            }
1305fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        };
1315fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1325fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromFile(root));
1335fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
1345fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
1355fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1365fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public void testTraverse() throws Exception {
1375fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DocumentTest test = new DocumentTest() {
1385fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            @Override
1395fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            public void exec(DocumentFile doc) throws Exception {
1405fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                resetRoot();
1415fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1425fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Root needs to at least contain our test file and dir
1435fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile foo = doc.findFile(FOO);
1445fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile meow = doc.findFile(MEOW);
1455fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("isFile", foo.isFile());
1465fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("isDirectory", meow.isDirectory());
1475fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1485fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Traverse inside, and expect to find exact number of items
1495fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                DocumentFile[] docs = meow.listFiles();
1505fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("length", 3, docs.length);
1515fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1525fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile cat = meow.findFile(CAT);
1535fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile dog = meow.findFile(DOG);
1545fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile bar = meow.findFile(BAR);
1555fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("isFile", cat.isFile());
1565fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("isFile", dog.isFile());
1575fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("isDirectory", bar.isDirectory());
1585fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1595fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Empty directory is empty
1605fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("length", 0, bar.listFiles().length);
1615fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            }
1625fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        };
1635fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1645fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromFile(root));
1655fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
1665fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
1675fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1685fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public void testReadAndWrite() throws Exception {
1695fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DocumentTest test = new DocumentTest() {
1705fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            @Override
1715fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            public void exec(DocumentFile doc) throws Exception {
1725fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                resetRoot();
1735fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1745fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile foo = doc.findFile(FOO);
1755fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("file", 12, readInt(rootFoo));
1765fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("uri", 12, readInt(foo.getUri()));
1775fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1785fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Underlying storage may not have sub-second resolution, so
1795fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // wait a few seconds.
1805fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                SystemClock.sleep(2000);
1815fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1825fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Ensure provider write makes its way to disk
1835fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final long beforeTime = foo.lastModified();
1845fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                writeInt(foo.getUri(), 13);
1855fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final long afterTime = foo.lastModified();
1865fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1875fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("file", 13, readInt(rootFoo));
1885fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("uri", 13, readInt(foo.getUri()));
1895fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1905fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Make sure we kicked time forward
1915fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("lastModified", afterTime > beforeTime);
1925fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            }
1935fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        };
1945fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1955fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromFile(root));
1965fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
1975fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
1985fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
1995fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public void testMimes() throws Exception {
2005fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DocumentTest test = new DocumentTest() {
2015fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            @Override
2025fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            public void exec(DocumentFile doc) throws Exception {
2035fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                resetRoot();
2045fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2055fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile foo = doc.findFile(FOO);
2065fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile meow = doc.findFile(MEOW);
2075fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile cat = meow.findFile(CAT);
2085fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile dog = meow.findFile(DOG);
2095fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile bar = meow.findFile(BAR);
2105fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2115fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals(null, doc.getType());
2125fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("application/octet-stream", foo.getType());
2135fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals(null, meow.getType());
2145fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("image/jpeg", cat.getType());
2155fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("application/pdf", dog.getType());
2165fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals(null, bar.getType());
2175fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            }
2185fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        };
2195fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2205fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromFile(root));
2215fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
2225fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
2235fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2245fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public void testCreate() throws Exception {
2255fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DocumentTest test = new DocumentTest() {
2265fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            @Override
2275fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            public void exec(DocumentFile doc) throws Exception {
2285fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                resetRoot();
2295fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2305fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile meow = doc.findFile(MEOW);
2315fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("length", 3, meow.listFiles().length);
2325fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2335fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Create file with MIME
2345fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile newFile = meow.createFile("text/plain", "My New File");
2355fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("My New File.txt", newFile.getName());
2365fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("text/plain", newFile.getType());
2375fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("isFile", newFile.isFile());
2385fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertFalse("isDirectory", newFile.isDirectory());
2395fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2405fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("length", 0, newFile.length());
2415fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                writeInt(newFile.getUri(), 0);
2425fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("length", 4, newFile.length());
2435fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2445fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Create raw file
2455fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile newRaw = meow.createFile("application/octet-stream",
2465fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                        "myrawfile");
2475fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("myrawfile", newRaw.getName());
2485fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("application/octet-stream", newRaw.getType());
2495fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("isFile", newRaw.isFile());
2505fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertFalse("isDirectory", newRaw.isDirectory());
2515fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2525fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Create directory
2535fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile newDir = meow.createDirectory("My New Directory.png");
2545fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("My New Directory.png", newDir.getName());
2555fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertFalse("isFile", newDir.isFile());
2565fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("isDirectory", newDir.isDirectory());
2575fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("length", 0, newDir.listFiles().length);
2585fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2595fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // And overall dir grew
2605fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("length", 6, meow.listFiles().length);
2615fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            }
2625fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        };
2635fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2645fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromFile(root));
2655fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
2665fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
2675fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2685fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public void testDelete() throws Exception {
2695fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DocumentTest test = new DocumentTest() {
2705fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            @Override
2715fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            public void exec(DocumentFile doc) throws Exception {
2725fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                resetRoot();
2735fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2745fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile meow = doc.findFile(MEOW);
2755fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile cat = meow.findFile(CAT);
2765fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                final DocumentFile dog = meow.findFile(DOG);
2775fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2785fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Delete single file
2795fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue(cat.delete());
2805fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertNull("cat", meow.findFile(CAT));
2815fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2825fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Other file still exists
2835fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue("exists", dog.exists());
2845fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2855fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Delete entire tree
2865fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue(meow.delete());
2875fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertNull("meow", doc.findFile(MEOW));
2885fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2895fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Nuking tree deleted other file
2905fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertFalse("exists", dog.exists());
2915fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            }
2925fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        };
2935fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2945fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromFile(root));
2955fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
2965fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
2975fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
2985fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    public void testRename() throws Exception {
2995fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DocumentTest test = new DocumentTest() {
3005fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            @Override
3015fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            public void exec(DocumentFile doc) throws Exception {
3025fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                resetRoot();
3035fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3045fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                DocumentFile meow = doc.findFile(MEOW);
3055fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                DocumentFile cat = meow.findFile(CAT);
3065fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                DocumentFile dog = meow.findFile(DOG);
3075fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue(dog.exists());
3085fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3095fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Rename a file
3105fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("cat.jpg", cat.getName());
3115fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("image/jpeg", cat.getType());
3125fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3135fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue(cat.renameTo("music.aAc"));
3145fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("music.aAc", cat.getName());
3155fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("audio/aac", cat.getType());
3165fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3175fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Rename a directory
3185fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("meow", meow.getName());
3195fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals(null, meow.getType());
3205fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue(meow.isDirectory());
3215fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals(3, meow.listFiles().length);
3225fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3235fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue(meow.renameTo("bark.pdf"));
3245fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals("bark.pdf", meow.getName());
3255fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals(null, meow.getType());
3265fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue(meow.isDirectory());
3275fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertEquals(3, meow.listFiles().length);
3285fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3295fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // Current implementation of ExternalStorageProvider invalidates
3305fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // all children documents when directory is renamed.
3315fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertFalse(dog.exists());
3325fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3335fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                // But we can find it again
3345fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                dog = meow.findFile(DOG);
3355fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                assertTrue(dog.exists());
3365fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            }
3375fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        };
3385fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3395fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromFile(root));
3405fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        test.exec(DocumentFile.fromTreeUri(getContext(), treeUri));
3415fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
3425fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3435fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private void writeInt(Uri uri, int value) throws IOException {
3445fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DataOutputStream os = new DataOutputStream(
3455fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                getContext().getContentResolver().openOutputStream(uri));
3465fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        try {
3475fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            os.writeInt(value);
3485fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        } finally {
3495fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            os.close();
3505fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        }
3515fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
3525fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3535fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private static void writeInt(File file, int value) throws IOException {
3545fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DataOutputStream os = new DataOutputStream(new FileOutputStream(file));
3555fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        try {
3565fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            os.writeInt(value);
3575fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        } finally {
3585fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            os.close();
3595fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        }
3605fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
3615fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3625fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private int readInt(Uri uri) throws IOException {
3635fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DataInputStream is = new DataInputStream(
3645fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey                getContext().getContentResolver().openInputStream(uri));
3655fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        try {
3665fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            return is.readInt();
3675fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        } finally {
3685fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            is.close();
3695fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        }
3705fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
3715fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey
3725fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    private static int readInt(File file) throws IOException {
3735fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        final DataInputStream is = new DataInputStream(new FileInputStream(file));
3745fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        try {
3755fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            return is.readInt();
3765fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        } finally {
3775fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey            is.close();
3785fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey        }
3795fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey    }
3805fdfbc2e02f46509474057e4366585f6a6062cb9Jeff Sharkey}
381