blob: 98610a0169e498ffc2a608e673de9781139786f5 [file] [log] [blame]
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.cts.documentclient;
18
19import android.content.ContentResolver;
20import android.content.Intent;
21import android.content.pm.PackageManager;
22import android.database.Cursor;
23import android.net.Uri;
24import android.os.SystemClock;
25import android.provider.DocumentsContract;
26import android.provider.DocumentsContract.Document;
27import android.provider.DocumentsProvider;
28import android.support.test.uiautomator.UiDevice;
29import android.support.test.uiautomator.UiObject;
Jeff Sharkeye837d822014-11-05 12:56:24 -080030import android.support.test.uiautomator.UiObjectNotFoundException;
31import android.support.test.uiautomator.UiScrollable;
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -070032import android.support.test.uiautomator.UiSelector;
33import android.test.InstrumentationTestCase;
34import android.test.MoreAsserts;
Jeff Sharkey5daa8492014-10-21 10:53:06 -070035import android.text.format.DateUtils;
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -070036
37import com.android.cts.documentclient.MyActivity.Result;
38
39import java.io.ByteArrayOutputStream;
40import java.io.FileNotFoundException;
41import java.io.IOException;
42import java.io.InputStream;
43import java.io.OutputStream;
44
45/**
46 * Tests for {@link DocumentsProvider} and interaction with platform intents
47 * like {@link Intent#ACTION_OPEN_DOCUMENT}.
48 */
49public class DocumentsClientTest extends InstrumentationTestCase {
50 private UiDevice mDevice;
51 private MyActivity mActivity;
52
Jeff Sharkey5daa8492014-10-21 10:53:06 -070053 private static final long TIMEOUT = 10 * DateUtils.SECOND_IN_MILLIS;
54
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -070055 @Override
56 public void setUp() throws Exception {
57 super.setUp();
58
59 mDevice = UiDevice.getInstance(getInstrumentation());
60 mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
61 MyActivity.class, null);
Jeff Sharkey69a1ee22014-10-15 16:52:29 -070062 mDevice.waitForIdle();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -070063 }
64
65 @Override
66 public void tearDown() throws Exception {
67 super.tearDown();
68 mActivity.finish();
69 }
70
Jeff Sharkeye837d822014-11-05 12:56:24 -080071 private UiObject findRoot(String label) throws UiObjectNotFoundException {
72 final UiSelector rootsList = new UiSelector().resourceId(
73 "com.android.documentsui:id/container_roots").childSelector(
74 new UiSelector().resourceId("android:id/list"));
75
76 // Wait for the first list item to appear
77 assertTrue("First list item",
78 new UiObject(rootsList.childSelector(new UiSelector())).waitForExists(TIMEOUT));
79
80 // Now scroll around to find our item
81 new UiScrollable(rootsList).scrollIntoView(new UiSelector().text(label));
82 return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
83 }
84
Jeff Sharkey4e9b7b52014-12-10 09:51:11 -080085 private UiObject findDocument(String label) throws UiObjectNotFoundException {
86 final UiSelector docList = new UiSelector().resourceId(
87 "com.android.documentsui:id/container_directory").childSelector(
88 new UiSelector().resourceId("com.android.documentsui:id/list"));
89
90 // Wait for the first list item to appear
91 assertTrue("First list item",
92 new UiObject(docList.childSelector(new UiSelector())).waitForExists(TIMEOUT));
93
94 // Now scroll around to find our item
95 new UiScrollable(docList).scrollIntoView(new UiSelector().text(label));
96 return new UiObject(docList.childSelector(new UiSelector().text(label)));
97 }
98
99 private UiObject findSaveButton() throws UiObjectNotFoundException {
100 return new UiObject(new UiSelector().resourceId("com.android.documentsui:id/container_save")
101 .childSelector(new UiSelector().resourceId("android:id/button1")));
102 }
103
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700104 public void testOpenSimple() throws Exception {
105 if (!supportedHardware()) return;
106
107 try {
108 // Opening without permission should fail
109 readFully(Uri.parse("content://com.android.cts.documentprovider/document/doc:file1"));
110 fail("Able to read data before opened!");
111 } catch (SecurityException expected) {
112 }
113
114 final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
115 intent.addCategory(Intent.CATEGORY_OPENABLE);
116 intent.setType("*/*");
117 mActivity.startActivityForResult(intent, 42);
118
119 // Ensure that we see both of our roots
Jeff Sharkey69a1ee22014-10-15 16:52:29 -0700120 mDevice.waitForIdle();
Jeff Sharkeye837d822014-11-05 12:56:24 -0800121 assertTrue("CtsLocal root", findRoot("CtsLocal").exists());
122 assertTrue("CtsCreate root", findRoot("CtsCreate").exists());
123 assertFalse("CtsGetContent root", findRoot("CtsGetContent").exists());
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700124
125 // Pick a specific file from our test provider
126 mDevice.waitForIdle();
Jeff Sharkeye837d822014-11-05 12:56:24 -0800127 findRoot("CtsLocal").click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700128
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700129 mDevice.waitForIdle();
Jeff Sharkey4e9b7b52014-12-10 09:51:11 -0800130 findDocument("FILE1").click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700131
132 final Result result = mActivity.getResult();
133 final Uri uri = result.data.getData();
134
135 // We should now have permission to read/write
136 MoreAsserts.assertEquals("fileone".getBytes(), readFully(uri));
137
138 writeFully(uri, "replaced!".getBytes());
139 SystemClock.sleep(500);
140 MoreAsserts.assertEquals("replaced!".getBytes(), readFully(uri));
141 }
142
143 public void testCreateNew() throws Exception {
144 if (!supportedHardware()) return;
145
146 final String DISPLAY_NAME = "My New Awesome Document Title";
147 final String MIME_TYPE = "image/png";
148
149 final Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
150 intent.addCategory(Intent.CATEGORY_OPENABLE);
151 intent.putExtra(Intent.EXTRA_TITLE, DISPLAY_NAME);
152 intent.setType(MIME_TYPE);
153 mActivity.startActivityForResult(intent, 42);
154
155 mDevice.waitForIdle();
Jeff Sharkeye837d822014-11-05 12:56:24 -0800156 findRoot("CtsCreate").click();
157
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700158 mDevice.waitForIdle();
Jeff Sharkey4e9b7b52014-12-10 09:51:11 -0800159 findSaveButton().click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700160
161 final Result result = mActivity.getResult();
162 final Uri uri = result.data.getData();
163
164 writeFully(uri, "meow!".getBytes());
165
166 assertEquals(DISPLAY_NAME, getColumn(uri, Document.COLUMN_DISPLAY_NAME));
167 assertEquals(MIME_TYPE, getColumn(uri, Document.COLUMN_MIME_TYPE));
168 }
169
170 public void testCreateExisting() throws Exception {
171 if (!supportedHardware()) return;
172
173 final Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
174 intent.addCategory(Intent.CATEGORY_OPENABLE);
175 intent.putExtra(Intent.EXTRA_TITLE, "NEVERUSED");
176 intent.setType("mime2/file2");
177 mActivity.startActivityForResult(intent, 42);
178
179 mDevice.waitForIdle();
Jeff Sharkeye837d822014-11-05 12:56:24 -0800180 findRoot("CtsCreate").click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700181
182 // Pick file2, which should be selected since MIME matches, then try
183 // picking a non-matching MIME, which should leave file2 selected.
184 mDevice.waitForIdle();
Jeff Sharkey4e9b7b52014-12-10 09:51:11 -0800185 findDocument("FILE2").click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700186 mDevice.waitForIdle();
Jeff Sharkey4e9b7b52014-12-10 09:51:11 -0800187 findDocument("FILE1").click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700188
Jeff Sharkey69a1ee22014-10-15 16:52:29 -0700189 mDevice.waitForIdle();
Jeff Sharkey4e9b7b52014-12-10 09:51:11 -0800190 findSaveButton().click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700191
192 final Result result = mActivity.getResult();
193 final Uri uri = result.data.getData();
194
195 MoreAsserts.assertEquals("filetwo".getBytes(), readFully(uri));
196 }
197
198 public void testTree() throws Exception {
199 if (!supportedHardware()) return;
200
201 final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
202 mActivity.startActivityForResult(intent, 42);
203
204 mDevice.waitForIdle();
Jeff Sharkeye837d822014-11-05 12:56:24 -0800205 findRoot("CtsCreate").click();
206
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700207 mDevice.waitForIdle();
Jeff Sharkey4e9b7b52014-12-10 09:51:11 -0800208 findDocument("DIR2").click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700209 mDevice.waitForIdle();
Jeff Sharkey4e9b7b52014-12-10 09:51:11 -0800210 findSaveButton().click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700211
212 final Result result = mActivity.getResult();
213 final Uri uri = result.data.getData();
214
215 // We should have selected DIR2
216 Uri doc = DocumentsContract.buildDocumentUriUsingTree(uri,
217 DocumentsContract.getTreeDocumentId(uri));
218 Uri children = DocumentsContract.buildChildDocumentsUriUsingTree(uri,
219 DocumentsContract.getTreeDocumentId(uri));
220
221 assertEquals("DIR2", getColumn(doc, Document.COLUMN_DISPLAY_NAME));
222
223 // Look around and make sure we can see children
224 final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
225 Cursor cursor = resolver.query(children, new String[] {
226 Document.COLUMN_DISPLAY_NAME }, null, null, null);
227 try {
228 assertEquals(1, cursor.getCount());
229 assertTrue(cursor.moveToFirst());
230 assertEquals("FILE4", cursor.getString(0));
231 } finally {
232 cursor.close();
233 }
234
235 // Create some documents
236 Uri pic = DocumentsContract.createDocument(resolver, doc, "image/png", "pic.png");
237 Uri dir = DocumentsContract.createDocument(resolver, doc, Document.MIME_TYPE_DIR, "my dir");
238 Uri dirPic = DocumentsContract.createDocument(resolver, dir, "image/png", "pic2.png");
239
240 writeFully(pic, "pic".getBytes());
241 writeFully(dirPic, "dirPic".getBytes());
242
243 // Read then delete existing doc
244 final Uri file4 = DocumentsContract.buildDocumentUriUsingTree(uri, "doc:file4");
245 MoreAsserts.assertEquals("filefour".getBytes(), readFully(file4));
246 assertTrue("delete", DocumentsContract.deleteDocument(resolver, file4));
247 try {
248 MoreAsserts.assertEquals("filefour".getBytes(), readFully(file4));
249 fail("Expected file to be gone");
250 } catch (FileNotFoundException expected) {
251 }
252
253 // And rename something
254 dirPic = DocumentsContract.renameDocument(resolver, dirPic, "wow");
255 assertNotNull("rename", dirPic);
256
257 // We should only see single child
258 assertEquals("wow", getColumn(dirPic, Document.COLUMN_DISPLAY_NAME));
259 MoreAsserts.assertEquals("dirPic".getBytes(), readFully(dirPic));
260
261 try {
262 // Make sure we can't see files outside selected dir
263 getColumn(DocumentsContract.buildDocumentUriUsingTree(uri, "doc:file1"),
264 Document.COLUMN_DISPLAY_NAME);
265 fail("Somehow read document outside tree!");
266 } catch (SecurityException expected) {
267 }
268 }
269
270 public void testGetContent() throws Exception {
271 if (!supportedHardware()) return;
272
273 final Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
274 intent.addCategory(Intent.CATEGORY_OPENABLE);
275 intent.setType("*/*");
276 mActivity.startActivityForResult(intent, 42);
277
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700278 // Look around, we should be able to see both DocumentsProviders and
279 // other GET_CONTENT sources.
Jeff Sharkey69a1ee22014-10-15 16:52:29 -0700280 mDevice.waitForIdle();
Jeff Sharkeye837d822014-11-05 12:56:24 -0800281 assertTrue("CtsLocal root", findRoot("CtsLocal").exists());
282 assertTrue("CtsCreate root", findRoot("CtsCreate").exists());
283 assertTrue("CtsGetContent root", findRoot("CtsGetContent").exists());
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700284
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700285 mDevice.waitForIdle();
Jeff Sharkeye837d822014-11-05 12:56:24 -0800286 findRoot("CtsGetContent").click();
Jeff Sharkey3c4d2fc2014-10-10 11:40:22 -0700287
288 final Result result = mActivity.getResult();
289 assertEquals("ReSuLt", result.data.getAction());
290 }
291
292 private String getColumn(Uri uri, String column) {
293 final ContentResolver resolver = getInstrumentation().getContext().getContentResolver();
294 final Cursor cursor = resolver.query(uri, new String[] { column }, null, null, null);
295 try {
296 assertTrue(cursor.moveToFirst());
297 return cursor.getString(0);
298 } finally {
299 cursor.close();
300 }
301 }
302
303 private byte[] readFully(Uri uri) throws IOException {
304 InputStream in = getInstrumentation().getContext().getContentResolver()
305 .openInputStream(uri);
306 try {
307 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
308 byte[] buffer = new byte[1024];
309 int count;
310 while ((count = in.read(buffer)) != -1) {
311 bytes.write(buffer, 0, count);
312 }
313 return bytes.toByteArray();
314 } finally {
315 in.close();
316 }
317 }
318
319 private void writeFully(Uri uri, byte[] data) throws IOException {
320 OutputStream out = getInstrumentation().getContext().getContentResolver()
321 .openOutputStream(uri);
322 try {
323 out.write(data);
324 } finally {
325 out.close();
326 }
327 }
328
329 private boolean supportedHardware() {
330 final PackageManager pm = getInstrumentation().getContext().getPackageManager();
331 if (pm.hasSystemFeature("android.hardware.type.television")
332 || pm.hasSystemFeature("android.hardware.type.watch")) {
333 return false;
334 }
335 return true;
336 }
337}