blob: 6d0da5a23f77301f230b08e9af4ac06fca6a0cb5 [file] [log] [blame]
/*
* Copyright (C) 2021 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.providers.media.photopicker;
import static android.provider.CloudMediaProviderContract.AlbumColumns.ALBUM_ID_FAVORITES;
import static android.provider.CloudMediaProviderContract.AlbumColumns.ALBUM_ID_VIDEOS;
import static com.android.providers.media.PickerProviderMediaGenerator.MediaGenerator;
import static com.android.providers.media.photopicker.data.PickerDbFacade.QueryFilterBuilder.LONG_DEFAULT;
import static com.android.providers.media.photopicker.data.PickerDbFacade.QueryFilterBuilder.STRING_DEFAULT;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.CloudMediaProviderContract.AlbumColumns;
import android.provider.CloudMediaProviderContract.MediaColumns;
import android.provider.MediaStore;
import android.util.Pair;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import com.android.modules.utils.BackgroundThread;
import com.android.providers.media.PickerProviderMediaGenerator;
import com.android.providers.media.TestConfigStore;
import com.android.providers.media.photopicker.data.PickerDatabaseHelper;
import com.android.providers.media.photopicker.data.PickerDbFacade;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@RunWith(AndroidJUnit4.class)
public class PickerDataLayerTest {
private static final String TAG = "PickerDataLayerTest";
private static final String PACKAGE_NAME = "com.android.providers.media.tests";
private static final String LOCAL_PROVIDER_AUTHORITY =
"com.android.providers.media.photopicker.tests.local";
private static final String CLOUD_PRIMARY_PROVIDER_AUTHORITY =
"com.android.providers.media.photopicker.tests.cloud_primary";
private static final String CLOUD_SECONDARY_PROVIDER_AUTHORITY =
"com.android.providers.media.photopicker.tests.cloud_secondary";
private final MediaGenerator mLocalMediaGenerator =
PickerProviderMediaGenerator.getMediaGenerator(LOCAL_PROVIDER_AUTHORITY);
private final MediaGenerator mCloudPrimaryMediaGenerator =
PickerProviderMediaGenerator.getMediaGenerator(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
private final MediaGenerator mCloudSecondaryMediaGenerator =
PickerProviderMediaGenerator.getMediaGenerator(CLOUD_SECONDARY_PROVIDER_AUTHORITY);
private static final int DB_VERSION_1 = 1;
private static final String DB_NAME = "test_db";
private static final String LOCAL_ID_1 = "1";
private static final String LOCAL_ID_2 = "2";
private static final String CLOUD_ID_1 = "1";
private static final String CLOUD_ID_2 = "2";
private static final String ALBUM_ID_1 = "1";
private static final String ALBUM_ID_2 = "2";
private static final String MIME_TYPE_DEFAULT = STRING_DEFAULT;
private static final long SIZE_BYTES_DEFAULT = LONG_DEFAULT;
private static final Pair<String, String> LOCAL_ONLY_1 = Pair.create(LOCAL_ID_1, null);
private static final Pair<String, String> LOCAL_ONLY_2 = Pair.create(LOCAL_ID_2, null);
private static final Pair<String, String> CLOUD_ONLY_1 = Pair.create(null, CLOUD_ID_1);
private static final Pair<String, String> CLOUD_ONLY_2 = Pair.create(null, CLOUD_ID_2);
private static final String COLLECTION_1 = "1";
private static final String IMAGE_MIME_TYPE = "image/jpeg";
private static final String VIDEO_MIME_TYPE = "video/mp4";
private static final long SIZE_BYTES = 50;
private Context mContext;
private PickerDatabaseHelper mDbHelper;
private PickerDbFacade mFacade;
private PickerDataLayer mDataLayer;
private PickerSyncController mController;
@Before
public void setUp() {
mLocalMediaGenerator.resetAll();
mCloudPrimaryMediaGenerator.resetAll();
mCloudSecondaryMediaGenerator.resetAll();
mLocalMediaGenerator.setMediaCollectionId(COLLECTION_1);
mCloudPrimaryMediaGenerator.setMediaCollectionId(COLLECTION_1);
mCloudSecondaryMediaGenerator.setMediaCollectionId(COLLECTION_1);
mContext = InstrumentationRegistry.getTargetContext();
// Delete db so it's recreated on next access and previous test state is cleared
final File dbPath = mContext.getDatabasePath(DB_NAME);
dbPath.delete();
mDbHelper = new PickerDatabaseHelper(mContext, DB_NAME, DB_VERSION_1);
mFacade = new PickerDbFacade(mContext, LOCAL_PROVIDER_AUTHORITY, mDbHelper);
final TestConfigStore configStore = new TestConfigStore();
configStore.enableCloudMediaFeatureAndSetAllowedCloudProviderPackages(PACKAGE_NAME);
configStore.setPickerSyncDelayMs(0);
mController = PickerSyncController.initialize(
mContext, mFacade, configStore, LOCAL_PROVIDER_AUTHORITY);
mDataLayer = new PickerDataLayer(mContext, mFacade, mController, configStore,
/* schedulePeriodicSyncs */ false);
// Set cloud provider to null to discard
mFacade.setCloudProvider(null);
}
@After
public void tearDown() {
if (mFacade != null) {
mFacade.setCloudProvider(null);
}
}
@Test
public void testFetchMediaNoFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1);
try (Cursor cr = mDataLayer.fetchAllMedia(buildDefaultQueryArgs())) {
assertThat(cr.getCount()).isEqualTo(2);
assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchMediaFavorites() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ true);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle defaultQueryArgs = buildDefaultQueryArgs();
try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(4);
}
final Bundle favoriteQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES,
LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT);
try (Cursor cr = mDataLayer.fetchAllMedia(favoriteQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(2);
assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchMediaFavoritesMimeTypeFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ true);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle defaultQueryArgs = buildDefaultQueryArgs();
try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(4);
}
final Bundle favoriteMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES,
LOCAL_PROVIDER_AUTHORITY, VIDEO_MIME_TYPE, SIZE_BYTES_DEFAULT);
try (Cursor cr = mDataLayer.fetchAllMedia(favoriteMimeTypeQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(1);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchMediaFavoritesSizeFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ true);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle defaultQueryArgs = buildDefaultQueryArgs();
try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(4);
}
final Bundle favoriteSizeQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES,
LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES - 1);
try (Cursor cr = mDataLayer.fetchAllMedia(favoriteSizeQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(1);
assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchMediaFavoritesMimeTypeAndSizeFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ true);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle defaultQueryArgs = buildDefaultQueryArgs();
try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(4);
}
final Bundle favoriteSizeAndMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES,
LOCAL_PROVIDER_AUTHORITY, VIDEO_MIME_TYPE, SIZE_BYTES - 1);
try (Cursor cr = mDataLayer.fetchAllMedia(favoriteSizeAndMimeTypeQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(0);
}
}
@Test
public void testFetchMediaMimeTypeFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle queryArgs = buildQueryArgs(IMAGE_MIME_TYPE, SIZE_BYTES_DEFAULT);
try (Cursor cr = mDataLayer.fetchAllMedia(queryArgs)) {
assertThat(cr.getCount()).isEqualTo(1);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchMediaSizeFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle queryArgs = buildQueryArgs(IMAGE_MIME_TYPE, SIZE_BYTES - 1);
try (Cursor cr = mDataLayer.fetchAllMedia(queryArgs)) {
assertThat(cr.getCount()).isEqualTo(1);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchMediaMimeTypeAndSizeFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle queryArgs = buildQueryArgs(VIDEO_MIME_TYPE, SIZE_BYTES - 1);
try (Cursor cr = mDataLayer.fetchAllMedia(queryArgs)) {
assertThat(cr.getCount()).isEqualTo(1);
assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchMediaLocalOnly() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1);
Bundle queryArgs = buildDefaultQueryArgs();
// Verify that we only see local content
try (Cursor cr = mDataLayer.fetchLocalMedia(queryArgs)) {
assertThat(cr.getCount()).isEqualTo(1);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
// Verify that we see cloud content
try (Cursor cr = mDataLayer.fetchAllMedia(queryArgs)) {
assertThat(cr.getCount()).isEqualTo(2);
assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchAlbumMedia() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
mLocalMediaGenerator.createAlbum(ALBUM_ID_1);
mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_2);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, ALBUM_ID_1, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_2, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumdId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true);
final Bundle defaultQueryArgs = buildDefaultQueryArgs();
try (Cursor cr = mDataLayer.fetchAllAlbums(defaultQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(4);
// Most recent media item marked as favorite will be the cover of the Favorites album.
// In this scenario, Favorites album cover was generated with cloud authority, so the
// Favorites album authority should be cloud provider authority. Similarly, the most
// recent video was generated with local authority, so the Videos album authority should
// be local provider authority.
assertAlbumCursor(cr, ALBUM_ID_FAVORITES, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
assertAlbumCursor(cr, ALBUM_ID_VIDEOS, LOCAL_PROVIDER_AUTHORITY);
assertAlbumCursor(cr, ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY);
assertAlbumCursor(cr, ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(4);
assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
final Bundle localAlbumQueryArgs = buildQueryArgs(ALBUM_ID_1,
LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT);
final Bundle cloudAlbumQueryArgs = buildQueryArgs(ALBUM_ID_2,
CLOUD_PRIMARY_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT);
final Bundle favoriteAlbumQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES,
LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT);
try (Cursor cr = mDataLayer.fetchAllMedia(localAlbumQueryArgs)) {
assertWithMessage("Local album count").that(cr.getCount()).isEqualTo(1);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
try (Cursor cr = mDataLayer.fetchAllMedia(cloudAlbumQueryArgs)) {
assertWithMessage("Cloud album count").that(cr.getCount()).isEqualTo(1);
assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
try (Cursor cr = mDataLayer.fetchAllMedia(favoriteAlbumQueryArgs)) {
assertWithMessage("Favorite album count").that(cr.getCount()).isEqualTo(2);
assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchAlbumMediaMimeTypeFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
mLocalMediaGenerator.createAlbum(ALBUM_ID_1);
mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_2);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, ALBUM_ID_1, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_2, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, ALBUM_ID_1, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, ALBUM_ID_2, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle mimeTypeQueryArgs = buildQueryArgs(IMAGE_MIME_TYPE, SIZE_BYTES_DEFAULT);
try (Cursor cr = mDataLayer.fetchAllAlbums(mimeTypeQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(2);
assertAlbumCursor(cr, ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY);
assertAlbumCursor(cr, ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
final Bundle localAlbumAndMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_1,
LOCAL_PROVIDER_AUTHORITY, IMAGE_MIME_TYPE, SIZE_BYTES_DEFAULT);
final Bundle cloudAlbumAndMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_2,
CLOUD_PRIMARY_PROVIDER_AUTHORITY, IMAGE_MIME_TYPE, SIZE_BYTES_DEFAULT);
try (Cursor cr = mDataLayer.fetchAllMedia(localAlbumAndMimeTypeQueryArgs)) {
assertWithMessage("Local album count").that(cr.getCount()).isEqualTo(1);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
try (Cursor cr = mDataLayer.fetchAllMedia(cloudAlbumAndMimeTypeQueryArgs)) {
assertWithMessage("Cloud album count").that(cr.getCount()).isEqualTo(1);
assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchAlbumMediaSizeFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
mLocalMediaGenerator.createAlbum(ALBUM_ID_1);
mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_2);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, ALBUM_ID_1, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_2, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ false);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, ALBUM_ID_1, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, ALBUM_ID_2, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle sizeQueryArgs = buildQueryArgs(MIME_TYPE_DEFAULT, SIZE_BYTES - 1);
try (Cursor cr = mDataLayer.fetchAllAlbums(sizeQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(3);
assertAlbumCursor(cr, ALBUM_ID_VIDEOS, LOCAL_PROVIDER_AUTHORITY);
assertAlbumCursor(cr, ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY);
assertAlbumCursor(cr, ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
final Bundle localAlbumAndSizeQueryArgs = buildQueryArgs(ALBUM_ID_1,
LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES -1);
final Bundle cloudAlbumAndSizeQueryArgs = buildQueryArgs(ALBUM_ID_2,
CLOUD_PRIMARY_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES -1);
try (Cursor cr = mDataLayer.fetchAllMedia(localAlbumAndSizeQueryArgs)) {
assertWithMessage("Local album count").that(cr.getCount()).isEqualTo(1);
assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY);
}
try (Cursor cr = mDataLayer.fetchAllMedia(cloudAlbumAndSizeQueryArgs)) {
assertWithMessage("Cloud album count").that(cr.getCount()).isEqualTo(1);
assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchAlbumMediaMimeTypeAndSizeFilter() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
mLocalMediaGenerator.createAlbum(ALBUM_ID_1);
mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_2);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, ALBUM_ID_1, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_2, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ false);
addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, ALBUM_ID_1, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1,
/* isFavorite */ false);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, ALBUM_ID_2, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
final Bundle mimeTypeAndSizeQueryArgs = buildQueryArgs(VIDEO_MIME_TYPE, SIZE_BYTES -1);
final Bundle cloudAlbumAndMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_2,
CLOUD_PRIMARY_PROVIDER_AUTHORITY, VIDEO_MIME_TYPE, SIZE_BYTES - 1);
try (Cursor cr = mDataLayer.fetchAllAlbums(mimeTypeAndSizeQueryArgs)) {
assertWithMessage("Merged and Local album count").that(cr.getCount()).isEqualTo(3);
// Most recent video will be the cover of the Videos album. In this scenario, Videos
// album cover was generated with cloud authority, so the Videos album authority should
// be cloud provider authority.
assertAlbumCursor(cr, ALBUM_ID_VIDEOS, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
assertAlbumCursor(cr, ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY);
assertAlbumCursor(cr, ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
try (Cursor cr = mDataLayer.fetchAllMedia(cloudAlbumAndMimeTypeQueryArgs)) {
assertWithMessage("Cloud album count").that(cr.getCount()).isEqualTo(1);
assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchAlbumMediaLocalOnly() {
mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
// Create a cloud album and add one cloud only item
mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_1);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_1, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false);
// Add one local only and one cloud only item and mark them favorite
addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true);
addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumdId */ null, IMAGE_MIME_TYPE,
MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true);
// Album Info:
// Album_ID_1 - Cloud Album - 1 Video File
// Videos - Merged Album - 2 Video Files (1 local + 1 cloud)
// Favorites - Merged Album - 2 files (1 local + 1 cloud)
final Bundle defaultQueryArgs = buildDefaultQueryArgs();
// Verify that we see both local and cloud albums
try (Cursor cr = mDataLayer.fetchAllAlbums(defaultQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(3);
}
// Verify that we only see local albums with isLocalOnly=true
try (Cursor cr = mDataLayer.fetchLocalAlbums(defaultQueryArgs)) {
assertThat(cr.getCount()).isEqualTo(2);
cr.moveToNext();
assertThat(cr.getString(cr.getColumnIndex(AlbumColumns.ID)))
.isEqualTo(ALBUM_ID_FAVORITES);
cr.moveToNext();
assertThat(cr.getString(cr.getColumnIndex(AlbumColumns.ID)))
.isEqualTo(ALBUM_ID_VIDEOS);
}
final Bundle favoriteAlbumQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES,
LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT);
try (Cursor cr = mDataLayer.fetchLocalMedia(favoriteAlbumQueryArgs)) {
assertWithMessage("Favorite album count").that(cr.getCount()).isEqualTo(1);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
// Verify that we get cloud content in Album Media when queried with localOnly=false
try (Cursor cr = mDataLayer.fetchAllMedia(favoriteAlbumQueryArgs)) {
assertWithMessage("Favorite album count").that(cr.getCount()).isEqualTo(2);
assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY);
assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY);
}
}
@Test
public void testFetchCloudAccountInfo() {
// Cloud provider is not set so cloud account info is null
assertThat(mDataLayer.fetchCloudAccountInfo()).isNull();
// Set cloud provider
mFacade.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY);
// Still null since cloud provider doesn't return account info yet
assertThat(mDataLayer.fetchCloudAccountInfo()).isNull();
// Fake cloud provider cloud account info
final String expectedName = "bar";
final Intent expectedIntent = new Intent("foo");
mCloudPrimaryMediaGenerator.setAccountInfo(expectedName, expectedIntent);
// Verify account info
final PickerDataLayer.AccountInfo info = mDataLayer.fetchCloudAccountInfo();
assertThat(info).isNotNull();
assertThat(info.accountName).isEqualTo(expectedName);
assertThat(info.accountConfigurationIntent).isEqualTo(expectedIntent);
}
private static void waitForIdle() {
final CountDownLatch latch = new CountDownLatch(1);
BackgroundThread.getExecutor().execute(() -> {
latch.countDown();
});
try {
latch.await(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
private static Bundle buildDefaultQueryArgs() {
return buildQueryArgs(MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT);
}
private static Bundle buildQueryArgs(String mimeType, long sizeBytes) {
final Bundle queryArgs = new Bundle();
if (mimeType != null) {
queryArgs.putStringArray(MediaStore.QUERY_ARG_MIME_TYPE, new String[]{mimeType});
}
queryArgs.putLong(MediaStore.QUERY_ARG_SIZE_BYTES, sizeBytes);
return queryArgs;
}
private static Bundle buildQueryArgs(String albumId, String albumAuthority, String mimeType,
long sizeBytes) {
final Bundle queryArgs = buildQueryArgs(mimeType, sizeBytes);
queryArgs.putString(MediaStore.QUERY_ARG_ALBUM_ID, albumId);
queryArgs.putString(MediaStore.QUERY_ARG_ALBUM_AUTHORITY, albumAuthority);
return queryArgs;
}
private static void addMedia(MediaGenerator generator, Pair<String, String> media) {
generator.addMedia(media.first, media.second);
}
private static void addMedia(MediaGenerator generator, Pair<String, String> media,
String albumId, String mimeType, int standardMimeTypeExtension, long sizeBytes,
boolean isFavorite) {
generator.addMedia(media.first, media.second, albumId, mimeType,
standardMimeTypeExtension, sizeBytes, isFavorite);
}
private static void deleteMedia(MediaGenerator generator, Pair<String, String> media) {
generator.deleteMedia(media.first, media.second);
}
private Cursor queryMedia() {
return mFacade.queryMediaForUi(
new PickerDbFacade.QueryFilterBuilder(1000).build());
}
private void assertEmptyCursor() {
try (Cursor cr = queryMedia()) {
assertThat(cr.getCount()).isEqualTo(0);
}
}
private static void assertAlbumCursor(Cursor cursor, String id, String expectedAuthority) {
cursor.moveToNext();
assertThat(cursor.getString(cursor.getColumnIndex(AlbumColumns.ID)))
.isEqualTo(id);
final int authorityIdx = cursor.getColumnIndex(AlbumColumns.AUTHORITY);
String authority = null;
if (authorityIdx >= 0) {
// Cursor from picker db has authority as a column
authority = cursor.getString(authorityIdx);
}
if (authority == null) {
// Cursor from provider directly doesn't have an authority column but will
// have the authority set as an extra
final Bundle bundle = cursor.getExtras();
authority = bundle.getString(MediaStore.EXTRA_CLOUD_PROVIDER);
}
assertThat(authority).isEqualTo(expectedAuthority);
}
private static void assertCursor(Cursor cursor, String id, String expectedAuthority) {
cursor.moveToNext();
assertThat(cursor.getString(cursor.getColumnIndex(MediaColumns.ID)))
.isEqualTo(id);
assertThat(cursor.getString(cursor.getColumnIndex(MediaColumns.AUTHORITY)))
.isEqualTo(expectedAuthority);
}
}