327 lines
13 KiB
Java
327 lines
13 KiB
Java
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.documentsui;
|
|
|
|
import static android.content.ContentResolver.wrap;
|
|
|
|
import static com.google.common.truth.Truth.assertThat;
|
|
|
|
import static junit.framework.Assert.assertEquals;
|
|
import static junit.framework.Assert.assertFalse;
|
|
import static junit.framework.Assert.assertNotNull;
|
|
import static junit.framework.Assert.assertNull;
|
|
import static junit.framework.Assert.assertTrue;
|
|
import static junit.framework.Assert.fail;
|
|
|
|
import android.content.ContentProviderClient;
|
|
import android.content.ContentResolver;
|
|
import android.content.Context;
|
|
import android.database.ContentObserver;
|
|
import android.database.Cursor;
|
|
import android.media.ExifInterface;
|
|
import android.net.Uri;
|
|
import android.os.Bundle;
|
|
import android.os.ParcelFileDescriptor;
|
|
import android.os.RemoteException;
|
|
import android.provider.DocumentsContract;
|
|
import android.text.TextUtils;
|
|
|
|
import androidx.test.InstrumentationRegistry;
|
|
import androidx.test.filters.MediumTest;
|
|
import androidx.test.runner.AndroidJUnit4;
|
|
|
|
import com.android.documentsui.archives.ArchivesProvider;
|
|
import com.android.documentsui.archives.ResourcesProvider;
|
|
|
|
import org.junit.After;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
@RunWith(AndroidJUnit4.class)
|
|
@MediumTest
|
|
public class ArchivesProviderTest {
|
|
|
|
private Context mContext;
|
|
private ExecutorService mExecutor = null;
|
|
|
|
@Before
|
|
public void setUp() throws Exception {
|
|
mContext = InstrumentationRegistry.getContext();
|
|
mExecutor = Executors.newSingleThreadExecutor();
|
|
}
|
|
|
|
@After
|
|
public void tearDown() throws Exception {
|
|
mExecutor.shutdown();
|
|
assertTrue(mExecutor.awaitTermination(3 /* timeout */, TimeUnit.SECONDS));
|
|
}
|
|
|
|
@Test
|
|
public void testQueryRoots() throws InterruptedException, RemoteException {
|
|
final ContentResolver resolver = mContext.getContentResolver();
|
|
final Uri rootsUri = DocumentsContract.buildRootsUri(ArchivesProvider.AUTHORITY);
|
|
try (ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
|
|
rootsUri)) {
|
|
Cursor cursor = client.query(rootsUri, null, null, null, null, null);
|
|
assertNotNull("Cursor must not be null.", cursor);
|
|
assertEquals(0, cursor.getCount());
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testOpen_Success() throws InterruptedException {
|
|
final Uri sourceUri = DocumentsContract.buildDocumentUri(
|
|
ResourcesProvider.AUTHORITY, "archive.zip");
|
|
final Uri archiveUri = ArchivesProvider.buildUriForArchive(sourceUri,
|
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
|
|
|
final Uri childrenUri = DocumentsContract.buildChildDocumentsUri(
|
|
ArchivesProvider.AUTHORITY, DocumentsContract.getDocumentId(archiveUri));
|
|
|
|
final ContentResolver resolver = mContext.getContentResolver();
|
|
final CountDownLatch latch = new CountDownLatch(1);
|
|
|
|
final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
|
|
archiveUri);
|
|
ArchivesProvider.acquireArchive(client, archiveUri);
|
|
|
|
{
|
|
final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
|
|
assertNotNull("Cursor must not be null. File not found?", cursor);
|
|
|
|
assertEquals(0, cursor.getCount());
|
|
final Bundle extras = cursor.getExtras();
|
|
assertEquals(true, extras.getBoolean(DocumentsContract.EXTRA_LOADING, false));
|
|
assertNull(extras.getString(DocumentsContract.EXTRA_ERROR));
|
|
|
|
final Uri notificationUri = cursor.getNotificationUri();
|
|
assertNotNull(notificationUri);
|
|
|
|
resolver.registerContentObserver(notificationUri, false, new ContentObserver(null) {
|
|
@Override
|
|
public void onChange(boolean selfChange, Uri uri) {
|
|
latch.countDown();
|
|
}
|
|
});
|
|
}
|
|
|
|
latch.await(3, TimeUnit.SECONDS);
|
|
{
|
|
final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
|
|
assertNotNull("Cursor must not be null. File not found?", cursor);
|
|
|
|
assertEquals(3, cursor.getCount());
|
|
final Bundle extras = cursor.getExtras();
|
|
assertEquals(false, extras.getBoolean(DocumentsContract.EXTRA_LOADING, false));
|
|
assertNull(extras.getString(DocumentsContract.EXTRA_ERROR));
|
|
}
|
|
|
|
ArchivesProvider.releaseArchive(client, archiveUri);
|
|
client.release();
|
|
}
|
|
|
|
@Test
|
|
public void testOpen_Failure() throws InterruptedException {
|
|
final Uri sourceUri = DocumentsContract.buildDocumentUri(
|
|
ResourcesProvider.AUTHORITY, "broken.zip");
|
|
final Uri archiveUri = ArchivesProvider.buildUriForArchive(sourceUri,
|
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
|
|
|
final Uri childrenUri = DocumentsContract.buildChildDocumentsUri(
|
|
ArchivesProvider.AUTHORITY, DocumentsContract.getDocumentId(archiveUri));
|
|
|
|
final ContentResolver resolver = mContext.getContentResolver();
|
|
final CountDownLatch latch = new CountDownLatch(1);
|
|
|
|
final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
|
|
archiveUri);
|
|
ArchivesProvider.acquireArchive(client, archiveUri);
|
|
|
|
{
|
|
// TODO: Close this and any other cursor in this file.
|
|
final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
|
|
assertNotNull("Cursor must not be null. File not found?", cursor);
|
|
|
|
assertEquals(0, cursor.getCount());
|
|
final Bundle extras = cursor.getExtras();
|
|
assertEquals(true, extras.getBoolean(DocumentsContract.EXTRA_LOADING, false));
|
|
assertNull(extras.getString(DocumentsContract.EXTRA_ERROR));
|
|
|
|
final Uri notificationUri = cursor.getNotificationUri();
|
|
assertNotNull(notificationUri);
|
|
|
|
resolver.registerContentObserver(notificationUri, false, new ContentObserver(null) {
|
|
@Override
|
|
public void onChange(boolean selfChange, Uri uri) {
|
|
latch.countDown();
|
|
}
|
|
});
|
|
}
|
|
|
|
latch.await(3, TimeUnit.SECONDS);
|
|
{
|
|
final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
|
|
assertNotNull("Cursor must not be null. File not found?", cursor);
|
|
|
|
assertEquals(0, cursor.getCount());
|
|
final Bundle extras = cursor.getExtras();
|
|
assertEquals(false, extras.getBoolean(DocumentsContract.EXTRA_LOADING, false));
|
|
assertFalse(TextUtils.isEmpty(extras.getString(DocumentsContract.EXTRA_ERROR)));
|
|
}
|
|
|
|
ArchivesProvider.releaseArchive(client, archiveUri);
|
|
client.release();
|
|
}
|
|
|
|
@Test
|
|
public void testOpen_ClosesOnRelease() throws InterruptedException {
|
|
final Uri sourceUri = DocumentsContract.buildDocumentUri(
|
|
ResourcesProvider.AUTHORITY, "archive.zip");
|
|
final Uri archiveUri = ArchivesProvider.buildUriForArchive(sourceUri,
|
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
|
|
|
final Uri childrenUri = DocumentsContract.buildChildDocumentsUri(
|
|
ArchivesProvider.AUTHORITY, DocumentsContract.getDocumentId(archiveUri));
|
|
|
|
final ContentResolver resolver = mContext.getContentResolver();
|
|
|
|
final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
|
|
archiveUri);
|
|
|
|
// Acquire twice to ensure that the refcount works correctly.
|
|
ArchivesProvider.acquireArchive(client, archiveUri);
|
|
ArchivesProvider.acquireArchive(client, archiveUri);
|
|
|
|
{
|
|
final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
|
|
assertNotNull("Cursor must not be null. File not found?", cursor);
|
|
}
|
|
|
|
ArchivesProvider.releaseArchive(client, archiveUri);
|
|
|
|
{
|
|
final Cursor cursor = resolver.query(childrenUri, null, null, null, null, null);
|
|
assertNotNull("Cursor must not be null. File not found?", cursor);
|
|
}
|
|
|
|
ArchivesProvider.releaseArchive(client, archiveUri);
|
|
|
|
try {
|
|
resolver.query(childrenUri, null, null, null, null, null);
|
|
fail("The archive was expected to be invalid on the last release call.");
|
|
} catch (IllegalStateException e) {
|
|
// Expected.
|
|
}
|
|
|
|
client.release();
|
|
}
|
|
|
|
@Test
|
|
public void testNoNotificationAfterAllReleased() throws InterruptedException, RemoteException {
|
|
final Uri sourceUri = DocumentsContract.buildDocumentUri(
|
|
ResourcesProvider.AUTHORITY, "archive.zip");
|
|
final Uri archiveUri = ArchivesProvider.buildUriForArchive(sourceUri,
|
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
|
|
|
final Uri childrenUri = DocumentsContract.buildChildDocumentsUri(
|
|
ArchivesProvider.AUTHORITY, DocumentsContract.getDocumentId(archiveUri));
|
|
|
|
final ContentResolver resolver = mContext.getContentResolver();
|
|
|
|
final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
|
|
archiveUri);
|
|
|
|
ArchivesProvider.acquireArchive(client, archiveUri);
|
|
final Cursor cursor = client.query(childrenUri, null, null, null, null, null);
|
|
final Bundle extra = cursor.getExtras();
|
|
assertTrue(extra.getBoolean(DocumentsContract.EXTRA_LOADING, false));
|
|
final Uri notificationUri = cursor.getNotificationUri();
|
|
|
|
ArchivesProvider.releaseArchive(client, archiveUri);
|
|
final CountDownLatch latch = new CountDownLatch(1);
|
|
resolver.registerContentObserver(notificationUri, false, new ContentObserver(null) {
|
|
@Override
|
|
public void onChange(boolean selfChange, Uri uri) {
|
|
latch.countDown();
|
|
}
|
|
});
|
|
|
|
// Assert that there is no notification if no one has acquired this archive and this wait
|
|
// times out.
|
|
assertFalse(latch.await(1, TimeUnit.SECONDS));
|
|
|
|
client.release();
|
|
}
|
|
|
|
private void getDocumentMetadata_byDocumentId_shouldMatchSize(String documentId)
|
|
throws Exception {
|
|
final Uri sourceUri = DocumentsContract.buildDocumentUri(
|
|
ResourcesProvider.AUTHORITY, documentId);
|
|
final Uri archiveUri = ArchivesProvider.buildUriForArchive(sourceUri,
|
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
|
|
|
final ContentResolver resolver = mContext.getContentResolver();
|
|
final ContentProviderClient client =
|
|
resolver.acquireUnstableContentProviderClient(archiveUri);
|
|
|
|
ArchivesProvider.acquireArchive(client, archiveUri);
|
|
|
|
Uri archivedImageUri = Uri.parse(
|
|
"content://com.android.documentsui.archives/document/content%3A%2F%2F"
|
|
+ "com.android.documentsui.archives.resourcesprovider%2F"
|
|
+ "document%2F" + documentId + "%23268435456%23%2Ffreddy.jpg");
|
|
|
|
Bundle metadata = DocumentsContract.getDocumentMetadata(wrap(client), archivedImageUri);
|
|
assertNotNull(metadata);
|
|
Bundle exif = metadata.getBundle(DocumentsContract.METADATA_EXIF);
|
|
assertNotNull(exif);
|
|
|
|
assertThat(exif.getInt(ExifInterface.TAG_IMAGE_WIDTH)).isEqualTo(3036);
|
|
assertThat(exif.getInt(ExifInterface.TAG_IMAGE_LENGTH)).isEqualTo(4048);
|
|
assertThat(exif.getString(ExifInterface.TAG_MODEL)).isEqualTo("Pixel");
|
|
|
|
ArchivesProvider.releaseArchive(client, archiveUri);
|
|
client.close();
|
|
}
|
|
|
|
@Test
|
|
public void testGetDocumentMetadata() throws Exception {
|
|
getDocumentMetadata_byDocumentId_shouldMatchSize("images.zip");
|
|
}
|
|
|
|
@Test
|
|
public void getDocumentMetadata_sevenZFile_shouldMatchSize() throws Exception {
|
|
getDocumentMetadata_byDocumentId_shouldMatchSize("images.7z");
|
|
}
|
|
|
|
@Test
|
|
public void getDocumentMetadata_tgz_shouldMatchSize() throws Exception {
|
|
getDocumentMetadata_byDocumentId_shouldMatchSize("images.tgz");
|
|
}
|
|
|
|
@Test
|
|
public void getDocumentMetadata_tar_shouldMatchSize() throws Exception {
|
|
getDocumentMetadata_byDocumentId_shouldMatchSize("images.tar");
|
|
}
|
|
}
|