1b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey/* 2b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * Copyright (C) 2013 The Android Open Source Project 3b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * 4b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * you may not use this file except in compliance with the License. 6b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * You may obtain a copy of the License at 7b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * 8b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * 10b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * Unless required by applicable law or agreed to in writing, software 11b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * See the License for the specific language governing permissions and 14b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * limitations under the License. 15b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey */ 16b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 17b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeypackage android.support.v4.content; 18b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 19b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport static android.provider.OpenableColumns.DISPLAY_NAME; 20b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport static android.provider.OpenableColumns.SIZE; 21b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 22b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.content.ContentResolver; 23b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.database.Cursor; 24b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.net.Uri; 25b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.os.Environment; 26b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.support.v4.content.FileProvider.SimplePathStrategy; 27b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.test.AndroidTestCase; 28b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport android.test.MoreAsserts; 292cb3bffdfbe47f5657821e5a12da9aab16b85c52Jeff Sharkey 30120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viveretteimport java.io.ByteArrayOutputStream; 312002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viveretteimport java.io.Closeable; 32b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.File; 33b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.FileNotFoundException; 34b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.FileOutputStream; 35120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viveretteimport java.io.IOException; 36b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.InputStream; 37b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeyimport java.io.OutputStream; 38b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 39b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey/** 40b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey * Tests for {@link FileProvider} 41b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey */ 42b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkeypublic class FileProviderTest extends AndroidTestCase { 43b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey private static final String TEST_AUTHORITY = "moocow"; 44b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 45b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey private static final String TEST_FILE = "file.test"; 46b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey private static final byte[] TEST_DATA = new byte[] { (byte) 0xf0, 0x00, 0x0d }; 47b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey private static final byte[] TEST_DATA_ALT = new byte[] { (byte) 0x33, 0x66 }; 48b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 49b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey private ContentResolver mResolver; 50b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 51b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey @Override 52b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey protected void setUp() throws Exception { 53b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey super.setUp(); 54b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 55b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey mResolver = getContext().getContentResolver(); 56b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 57b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 58b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testStrategyUriSimple() throws Exception { 59b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final SimplePathStrategy strat = new SimplePathStrategy("authority"); 60b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag", mContext.getFilesDir()); 61b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 62b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey File file = buildPath(mContext.getFilesDir(), "file.test"); 63b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://authority/tag/file.test", 64b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getUriForFile(file).toString()); 65b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 66b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey file = buildPath(mContext.getFilesDir(), "subdir", "file.test"); 67b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://authority/tag/subdir/file.test", 68b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getUriForFile(file).toString()); 69b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 70b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey file = buildPath(Environment.getExternalStorageDirectory(), "file.test"); 71b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 72b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getUriForFile(file); 73b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey fail("somehow got uri for file outside roots?"); 74b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } catch (IllegalArgumentException e) { 75b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 76b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 77b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 78b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testStrategyUriJumpOutside() throws Exception { 79b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final SimplePathStrategy strat = new SimplePathStrategy("authority"); 80b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag", mContext.getFilesDir()); 81b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 82b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey File file = buildPath(mContext.getFilesDir(), "..", "file.test"); 83b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 84b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getUriForFile(file); 85b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey fail("file escaped!"); 86b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } catch (IllegalArgumentException e) { 87b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 88b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 89b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 90b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testStrategyUriShortestRoot() throws Exception { 91b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey SimplePathStrategy strat = new SimplePathStrategy("authority"); 92b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag1", mContext.getFilesDir()); 93b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag2", new File("/")); 94b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 95b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey File file = buildPath(mContext.getFilesDir(), "file.test"); 96b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://authority/tag1/file.test", 97b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getUriForFile(file).toString()); 98b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 99b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat = new SimplePathStrategy("authority"); 100b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag1", new File("/")); 101b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag2", mContext.getFilesDir()); 102b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 103b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey file = buildPath(mContext.getFilesDir(), "file.test"); 104b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://authority/tag2/file.test", 105b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getUriForFile(file).toString()); 106b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 107b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 108b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testStrategyFileSimple() throws Exception { 109b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final SimplePathStrategy strat = new SimplePathStrategy("authority"); 110b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag", mContext.getFilesDir()); 111b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 1122002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File expectedRoot = mContext.getFilesDir().getCanonicalFile(); 1132002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File file = buildPath(expectedRoot, "file.test"); 114b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(file.getPath(), 115b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getFileForUri(Uri.parse("content://authority/tag/file.test")).getPath()); 116b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 1172002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette file = buildPath(expectedRoot, "subdir", "file.test"); 118b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(file.getPath(), strat.getFileForUri( 119b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey Uri.parse("content://authority/tag/subdir/file.test")).getPath()); 120b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 121b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 122b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testStrategyFileJumpOutside() throws Exception { 123b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final SimplePathStrategy strat = new SimplePathStrategy("authority"); 124b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag", mContext.getFilesDir()); 125b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 126b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 127b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getFileForUri(Uri.parse("content://authority/tag/../file.test")); 128b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey fail("file escaped!"); 129b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } catch (SecurityException e) { 130b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 131b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 132b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 133b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testStrategyEscaping() throws Exception { 134b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final SimplePathStrategy strat = new SimplePathStrategy("authority"); 135b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("t/g", mContext.getFilesDir()); 136b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 1372002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File expectedRoot = mContext.getFilesDir().getCanonicalFile(); 1382002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File file = buildPath(expectedRoot, "lol\"wat?foo&bar", "wat.txt"); 139b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final String expected = "content://authority/t%2Fg/lol%22wat%3Ffoo%26bar/wat.txt"; 140b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 141b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(expected, 142b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getUriForFile(file).toString()); 143b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(file.getPath(), 144b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getFileForUri(Uri.parse(expected)).getPath()); 145b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 146b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 147b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testStrategyExtraParams() throws Exception { 148b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final SimplePathStrategy strat = new SimplePathStrategy("authority"); 149b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag", mContext.getFilesDir()); 150b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 1512002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File expectedRoot = mContext.getFilesDir().getCanonicalFile(); 1522002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File file = buildPath(expectedRoot, "file.txt"); 153b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(file.getPath(), strat.getFileForUri( 154b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey Uri.parse("content://authority/tag/file.txt?extra=foo")).getPath()); 155b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 156b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 157b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testStrategyExtraSeparators() throws Exception { 158b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final SimplePathStrategy strat = new SimplePathStrategy("authority"); 159b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.addRoot("tag", mContext.getFilesDir()); 160b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 161b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey // When canonicalized, the path separators are trimmed 162b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey File inFile = new File(mContext.getFilesDir(), "//foo//bar//"); 1632002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File expectedRoot = mContext.getFilesDir().getCanonicalFile(); 1642002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File outFile = new File(expectedRoot, "/foo/bar"); 165b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final String expected = "content://authority/tag/foo/bar"; 166b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 167b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(expected, 168b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getUriForFile(inFile).toString()); 169b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(outFile.getPath(), 170b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey strat.getFileForUri(Uri.parse(expected)).getPath()); 171b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 172b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 173b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testQueryProjectionNull() throws Exception { 174b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final File file = new File(mContext.getFilesDir(), TEST_FILE); 175b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final Uri uri = stageFileAndGetUri(file, TEST_DATA); 176b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 177b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey // Verify that null brings out default columns 178b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey Cursor cursor = mResolver.query(uri, null, null, null, null); 179b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 180b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(1, cursor.getCount()); 181b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cursor.moveToFirst(); 182b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(TEST_FILE, cursor.getString(cursor.getColumnIndex(DISPLAY_NAME))); 183b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(TEST_DATA.length, cursor.getLong(cursor.getColumnIndex(SIZE))); 184b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } finally { 185b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cursor.close(); 186b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 187b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 188b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 189b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testQueryProjectionOrder() throws Exception { 190b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final File file = new File(mContext.getFilesDir(), TEST_FILE); 191b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final Uri uri = stageFileAndGetUri(file, TEST_DATA); 192b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 193b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey // Verify that swapped order works 194b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey Cursor cursor = mResolver.query(uri, new String[] { 195b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey SIZE, DISPLAY_NAME }, null, null, null); 196b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 197b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(1, cursor.getCount()); 198b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cursor.moveToFirst(); 199b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(TEST_DATA.length, cursor.getLong(0)); 200b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(TEST_FILE, cursor.getString(1)); 201b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } finally { 202b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cursor.close(); 203b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 204b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 205b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cursor = mResolver.query(uri, new String[] { 206b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey DISPLAY_NAME, SIZE }, null, null, null); 207b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 208b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(1, cursor.getCount()); 209b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cursor.moveToFirst(); 210b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(TEST_FILE, cursor.getString(0)); 211b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(TEST_DATA.length, cursor.getLong(1)); 212b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } finally { 213b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cursor.close(); 214b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 215b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 216b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 217b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testQueryExtraColumn() throws Exception { 218b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final File file = new File(mContext.getFilesDir(), TEST_FILE); 219b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final Uri uri = stageFileAndGetUri(file, TEST_DATA); 220b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 221b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey // Verify that extra column doesn't gook things up 222b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey Cursor cursor = mResolver.query(uri, new String[] { 223b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey SIZE, "foobar", DISPLAY_NAME }, null, null, null); 224b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 225b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(1, cursor.getCount()); 226b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cursor.moveToFirst(); 227b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(TEST_DATA.length, cursor.getLong(0)); 228b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(TEST_FILE, cursor.getString(1)); 229b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } finally { 230b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cursor.close(); 231b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 232b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 233b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 234b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testReadFile() throws Exception { 235b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final File file = new File(mContext.getFilesDir(), TEST_FILE); 236b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final Uri uri = stageFileAndGetUri(file, TEST_DATA); 237b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 238b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertContentsEquals(TEST_DATA, uri); 239b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 240b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 241b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testWriteFile() throws Exception { 242b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final File file = new File(mContext.getFilesDir(), TEST_FILE); 243b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final Uri uri = stageFileAndGetUri(file, TEST_DATA); 244b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 245b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertContentsEquals(TEST_DATA, uri); 246b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 247b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final OutputStream out = mResolver.openOutputStream(uri); 248b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 249b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey out.write(TEST_DATA_ALT); 250b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } finally { 251120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette closeQuietly(out); 252b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 253b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 254b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertContentsEquals(TEST_DATA_ALT, uri); 255b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 256b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 257b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testWriteMissingFile() throws Exception { 258b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final File file = new File(mContext.getFilesDir(), TEST_FILE); 259b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final Uri uri = stageFileAndGetUri(file, null); 260b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 261b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 262b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertContentsEquals(new byte[0], uri); 263b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey fail("Somehow read missing file?"); 264b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } catch(FileNotFoundException e) { 265b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 266b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 267b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final OutputStream out = mResolver.openOutputStream(uri); 268b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 269b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey out.write(TEST_DATA_ALT); 270b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } finally { 271120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette closeQuietly(out); 272b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 273b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 274b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertContentsEquals(TEST_DATA_ALT, uri); 275b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 276b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 277b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testDelete() throws Exception { 278b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final File file = new File(mContext.getFilesDir(), TEST_FILE); 279b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final Uri uri = stageFileAndGetUri(file, TEST_DATA); 280b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 281b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertContentsEquals(TEST_DATA, uri); 282b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 283b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(1, mResolver.delete(uri, null, null)); 284b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals(0, mResolver.delete(uri, null, null)); 285b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 286b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 287b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertContentsEquals(new byte[0], uri); 288b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey fail("Somehow read missing file?"); 289b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } catch(FileNotFoundException e) { 290b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 291b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 292b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 293b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey public void testMetaDataTargets() { 294b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey Uri actual; 295b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 296b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY, 297b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey new File("/proc/version")); 298b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://moocow/test_root/proc/version", actual.toString()); 299b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 300b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY, 301b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey new File("/proc/1/mountinfo")); 302b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://moocow/test_init/mountinfo", actual.toString()); 303b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 304b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY, 305b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey buildPath(mContext.getFilesDir(), "meow")); 306b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://moocow/test_files/meow", actual.toString()); 307b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 308b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY, 309b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey buildPath(mContext.getFilesDir(), "thumbs", "rawr")); 310b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://moocow/test_thumbs/rawr", actual.toString()); 311b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 312b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY, 313b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey buildPath(mContext.getCacheDir(), "up", "down")); 314b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://moocow/test_cache/up/down", actual.toString()); 315b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 316b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY, 317b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey buildPath(Environment.getExternalStorageDirectory(), "Android", "obb", "foobar")); 318b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey assertEquals("content://moocow/test_external/Android/obb/foobar", actual.toString()); 3192002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette 3202002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File[] externalFilesDirs = ContextCompat.getExternalFilesDirs(mContext, null); 3212002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY, 3222002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette buildPath(externalFilesDirs[0], "foo", "bar")); 3232002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette assertEquals("content://moocow/test_external_files/foo/bar", actual.toString()); 3242002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette 3252002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette File[] externalCacheDirs = ContextCompat.getExternalCacheDirs(mContext); 3262002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette actual = FileProvider.getUriForFile(mContext, TEST_AUTHORITY, 3272002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette buildPath(externalCacheDirs[0], "foo", "bar")); 3282002bed7d4769fc985b7a8e8b5ba875ffc7e829aAlan Viverette assertEquals("content://moocow/test_external_cache/foo/bar", actual.toString()); 329b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 330b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 331b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey private void assertContentsEquals(byte[] expected, Uri actual) throws Exception { 332b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final InputStream in = mResolver.openInputStream(actual); 333b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 334120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette MoreAsserts.assertEquals(expected, readFully(in)); 335b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } finally { 336120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette closeQuietly(in); 337b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 338b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 339b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 340b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey private Uri stageFileAndGetUri(File file, byte[] data) throws Exception { 341b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey if (data != null) { 342b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey final FileOutputStream out = new FileOutputStream(file); 343b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey try { 344b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey out.write(data); 345b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } finally { 346b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey out.close(); 347b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 348b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } else { 349b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey file.delete(); 350b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 351b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey return FileProvider.getUriForFile(mContext, TEST_AUTHORITY, file); 352b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 353b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey 354b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey private static File buildPath(File base, String... segments) { 355b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey File cur = base; 356b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey for (String segment : segments) { 357b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey if (cur == null) { 358b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cur = new File(segment); 359b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } else { 360b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey cur = new File(cur, segment); 361b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 362b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 363b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey return cur; 364b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey } 365120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette 366120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette /** 367120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette * Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null. 368120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette */ 369120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette private static void closeQuietly(AutoCloseable closeable) { 370120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette if (closeable != null) { 371120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette try { 372120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette closeable.close(); 373120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } catch (RuntimeException rethrown) { 374120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette throw rethrown; 375120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } catch (Exception ignored) { 376120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } 377120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } 378120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } 379120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette 380120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette /** 381120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette * Returns a byte[] containing the remainder of 'in', closing it when done. 382120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette */ 383120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette private static byte[] readFully(InputStream in) throws IOException { 384120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette try { 385120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette return readFullyNoClose(in); 386120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } finally { 387120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette in.close(); 388120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } 389120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } 390120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette 391120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette /** 392120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette * Returns a byte[] containing the remainder of 'in'. 393120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette */ 394120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette private static byte[] readFullyNoClose(InputStream in) throws IOException { 395120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 396120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette byte[] buffer = new byte[1024]; 397120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette int count; 398120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette while ((count = in.read(buffer)) != -1) { 399120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette bytes.write(buffer, 0, count); 400120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } 401120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette return bytes.toByteArray(); 402120325c4bd854c49fa50b872bdd84a7fac58210cAlan Viverette } 403b49cb25e1450ae36d2559e9753c6d5064e530fccJeff Sharkey} 404