1 /* 2 * Copyright (C) 2021 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 17 package com.android.providers.media.photopicker; 18 19 import static android.provider.CloudMediaProviderContract.AlbumColumns.ALBUM_ID_FAVORITES; 20 import static android.provider.CloudMediaProviderContract.AlbumColumns.ALBUM_ID_VIDEOS; 21 22 import static com.android.providers.media.PickerProviderMediaGenerator.MediaGenerator; 23 import static com.android.providers.media.photopicker.data.PickerDbFacade.QueryFilterBuilder.LONG_DEFAULT; 24 import static com.android.providers.media.photopicker.data.PickerDbFacade.QueryFilterBuilder.STRING_DEFAULT; 25 import static com.android.providers.media.photopicker.sync.SyncWorkerTestUtils.initializeTestWorkManager; 26 27 import static com.google.common.truth.Truth.assertThat; 28 import static com.google.common.truth.Truth.assertWithMessage; 29 30 import static org.junit.Assert.assertThrows; 31 32 import android.content.Context; 33 import android.content.Intent; 34 import android.database.Cursor; 35 import android.os.Bundle; 36 import android.provider.CloudMediaProviderContract.AlbumColumns; 37 import android.provider.CloudMediaProviderContract.MediaColumns; 38 import android.provider.MediaStore; 39 import android.util.Pair; 40 41 import androidx.annotation.NonNull; 42 import androidx.test.InstrumentationRegistry; 43 import androidx.test.runner.AndroidJUnit4; 44 import androidx.work.WorkManager; 45 46 import com.android.modules.utils.BackgroundThread; 47 import com.android.providers.media.PickerProviderMediaGenerator; 48 import com.android.providers.media.TestConfigStore; 49 import com.android.providers.media.photopicker.data.CloudProviderInfo; 50 import com.android.providers.media.photopicker.data.PickerDatabaseHelper; 51 import com.android.providers.media.photopicker.data.PickerDbFacade; 52 import com.android.providers.media.photopicker.data.PickerSyncRequestExtras; 53 import com.android.providers.media.photopicker.sync.PickerSyncLockManager; 54 import com.android.providers.media.photopicker.sync.PickerSyncManager; 55 import com.android.providers.media.util.ForegroundThread; 56 57 import org.junit.After; 58 import org.junit.Before; 59 import org.junit.Test; 60 import org.junit.runner.RunWith; 61 62 import java.io.File; 63 import java.util.concurrent.CountDownLatch; 64 import java.util.concurrent.TimeUnit; 65 66 @RunWith(AndroidJUnit4.class) 67 public class PickerDataLayerTest { 68 private static final String TAG = "PickerDataLayerTest"; 69 70 private static final String PACKAGE_NAME = "com.android.providers.media.tests"; 71 private static final String LOCAL_PROVIDER_AUTHORITY = 72 "com.android.providers.media.photopicker.tests.local"; 73 private static final String CLOUD_PRIMARY_PROVIDER_AUTHORITY = 74 "com.android.providers.media.photopicker.tests.cloud_primary"; 75 private static final String CLOUD_SECONDARY_PROVIDER_AUTHORITY = 76 "com.android.providers.media.photopicker.tests.cloud_secondary"; 77 78 private final MediaGenerator mLocalMediaGenerator = 79 PickerProviderMediaGenerator.getMediaGenerator(LOCAL_PROVIDER_AUTHORITY); 80 private final MediaGenerator mCloudPrimaryMediaGenerator = 81 PickerProviderMediaGenerator.getMediaGenerator(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 82 private final MediaGenerator mCloudSecondaryMediaGenerator = 83 PickerProviderMediaGenerator.getMediaGenerator(CLOUD_SECONDARY_PROVIDER_AUTHORITY); 84 85 private static final int DB_VERSION_1 = 1; 86 private static final String DB_NAME = "test_db"; 87 88 private static final String LOCAL_ID_1 = "1"; 89 private static final String LOCAL_ID_2 = "2"; 90 91 private static final String CLOUD_ID_1 = "1"; 92 private static final String CLOUD_ID_2 = "2"; 93 94 private static final String ALBUM_ID_1 = "1"; 95 private static final String ALBUM_ID_2 = "2"; 96 97 private static final String MIME_TYPE_DEFAULT = STRING_DEFAULT; 98 private static final long SIZE_BYTES_DEFAULT = LONG_DEFAULT; 99 100 private static final Pair<String, String> LOCAL_ONLY_1 = Pair.create(LOCAL_ID_1, null); 101 private static final Pair<String, String> LOCAL_ONLY_2 = Pair.create(LOCAL_ID_2, null); 102 private static final Pair<String, String> CLOUD_ONLY_1 = Pair.create(null, CLOUD_ID_1); 103 private static final Pair<String, String> CLOUD_ONLY_2 = Pair.create(null, CLOUD_ID_2); 104 105 private static final String COLLECTION_1 = "1"; 106 107 private static final String IMAGE_MIME_TYPE = "image/jpeg"; 108 private static final String VIDEO_MIME_TYPE = "video/mp4"; 109 private static final long SIZE_BYTES = 50; 110 111 private Context mContext; 112 private PickerDatabaseHelper mDbHelper; 113 private PickerDbFacade mFacade; 114 private PickerDataLayer mDataLayer; 115 private PickerSyncController mController; 116 private TestConfigStore mConfigStore; 117 118 @Before setUp()119 public void setUp() { 120 mLocalMediaGenerator.resetAll(); 121 mCloudPrimaryMediaGenerator.resetAll(); 122 mCloudSecondaryMediaGenerator.resetAll(); 123 124 mLocalMediaGenerator.setMediaCollectionId(COLLECTION_1); 125 mCloudPrimaryMediaGenerator.setMediaCollectionId(COLLECTION_1); 126 mCloudSecondaryMediaGenerator.setMediaCollectionId(COLLECTION_1); 127 128 mContext = InstrumentationRegistry.getTargetContext(); 129 130 // Delete db so it's recreated on next access and previous test state is cleared 131 final File dbPath = mContext.getDatabasePath(DB_NAME); 132 dbPath.delete(); 133 134 final PickerSyncLockManager lockManager = new PickerSyncLockManager(); 135 136 mDbHelper = new PickerDatabaseHelper(mContext, DB_NAME, DB_VERSION_1); 137 mFacade = new PickerDbFacade(mContext, lockManager, LOCAL_PROVIDER_AUTHORITY, mDbHelper); 138 139 mConfigStore = new TestConfigStore(); 140 mConfigStore.enableCloudMediaFeatureAndSetAllowedCloudProviderPackages(PACKAGE_NAME); 141 142 mController = PickerSyncController.initialize( 143 mContext, mFacade, mConfigStore, lockManager, LOCAL_PROVIDER_AUTHORITY); 144 145 initializeTestWorkManager(mContext); 146 final WorkManager workManager = WorkManager.getInstance(mContext); 147 final PickerSyncManager syncManager = new PickerSyncManager( 148 workManager, mContext, mConfigStore, /* schedulePeriodicSyncs */ false); 149 mDataLayer = new PickerDataLayer(mContext, mFacade, mController, mConfigStore, syncManager); 150 151 // Set cloud provider to null to discard 152 mFacade.setCloudProvider(null); 153 } 154 155 @After tearDown()156 public void tearDown() { 157 if (mFacade != null) { 158 mFacade.setCloudProvider(null); 159 } 160 } 161 162 @Test testFetchMediaNoFilter()163 public void testFetchMediaNoFilter() { 164 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 165 166 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1); 167 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1); 168 169 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 170 mDataLayer.initMediaData(syncRequestExtras); 171 try (Cursor cr = mDataLayer.fetchAllMedia(buildDefaultQueryArgs())) { 172 assertThat(cr.getCount()).isEqualTo(2); 173 174 assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 175 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 176 } 177 } 178 179 @Test testFetchMediaFavorites()180 public void testFetchMediaFavorites() { 181 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 182 183 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE, 184 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true); 185 addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE, 186 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 187 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE, 188 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 189 /* isFavorite */ true); 190 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE, 191 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 192 193 final Bundle defaultQueryArgs = buildDefaultQueryArgs(); 194 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 195 mDataLayer.initMediaData(syncRequestExtras); 196 197 try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) { 198 assertThat(cr.getCount()).isEqualTo(4); 199 } 200 201 final Bundle favoriteQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES, 202 LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT); 203 204 try (Cursor cr = mDataLayer.fetchAllMedia(favoriteQueryArgs)) { 205 assertThat(cr.getCount()).isEqualTo(2); 206 207 assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 208 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 209 } 210 } 211 212 @Test testFetchMediaFavoritesMimeTypeFilter()213 public void testFetchMediaFavoritesMimeTypeFilter() { 214 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 215 216 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE, 217 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true); 218 addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE, 219 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 220 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE, 221 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 222 /* isFavorite */ true); 223 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE, 224 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 225 226 final Bundle defaultQueryArgs = buildDefaultQueryArgs(); 227 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 228 mDataLayer.initMediaData(syncRequestExtras); 229 230 try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) { 231 assertThat(cr.getCount()).isEqualTo(4); 232 } 233 234 final Bundle favoriteMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES, 235 LOCAL_PROVIDER_AUTHORITY, VIDEO_MIME_TYPE, SIZE_BYTES_DEFAULT); 236 237 try (Cursor cr = mDataLayer.fetchAllMedia(favoriteMimeTypeQueryArgs)) { 238 assertThat(cr.getCount()).isEqualTo(1); 239 240 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 241 } 242 } 243 244 @Test testFetchMediaFavoritesSizeFilter()245 public void testFetchMediaFavoritesSizeFilter() { 246 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 247 248 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE, 249 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true); 250 addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE, 251 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 252 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE, 253 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 254 /* isFavorite */ true); 255 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE, 256 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 257 258 final Bundle defaultQueryArgs = buildDefaultQueryArgs(); 259 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 260 mDataLayer.initMediaData(syncRequestExtras); 261 262 try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) { 263 assertThat(cr.getCount()).isEqualTo(4); 264 } 265 266 final Bundle favoriteSizeQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES, 267 LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES - 1); 268 269 try (Cursor cr = mDataLayer.fetchAllMedia(favoriteSizeQueryArgs)) { 270 assertThat(cr.getCount()).isEqualTo(1); 271 272 assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 273 } 274 } 275 276 @Test testFetchMediaFavoritesMimeTypeAndSizeFilter()277 public void testFetchMediaFavoritesMimeTypeAndSizeFilter() { 278 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 279 280 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE, 281 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true); 282 addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE, 283 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 284 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE, 285 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 286 /* isFavorite */ true); 287 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, IMAGE_MIME_TYPE, 288 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 289 290 final Bundle defaultQueryArgs = buildDefaultQueryArgs(); 291 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 292 mDataLayer.initMediaData(syncRequestExtras); 293 294 try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) { 295 assertThat(cr.getCount()).isEqualTo(4); 296 } 297 298 final Bundle favoriteSizeAndMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES, 299 LOCAL_PROVIDER_AUTHORITY, VIDEO_MIME_TYPE, SIZE_BYTES - 1); 300 301 try (Cursor cr = mDataLayer.fetchAllMedia(favoriteSizeAndMimeTypeQueryArgs)) { 302 assertThat(cr.getCount()).isEqualTo(0); 303 } 304 } 305 306 @Test testFetchMediaMimeTypeFilter()307 public void testFetchMediaMimeTypeFilter() { 308 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 309 310 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE, 311 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 312 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE, 313 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 314 315 final Bundle queryArgs = buildQueryArgs(IMAGE_MIME_TYPE, SIZE_BYTES_DEFAULT); 316 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 317 mDataLayer.initMediaData(syncRequestExtras); 318 319 try (Cursor cr = mDataLayer.fetchAllMedia(queryArgs)) { 320 assertThat(cr.getCount()).isEqualTo(1); 321 322 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 323 } 324 } 325 326 @Test testFetchMediaSizeFilter()327 public void testFetchMediaSizeFilter() { 328 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 329 330 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE, 331 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 332 /* isFavorite */ false); 333 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE, 334 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 335 336 final Bundle queryArgs = buildQueryArgs(IMAGE_MIME_TYPE, SIZE_BYTES - 1); 337 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 338 mDataLayer.initMediaData(syncRequestExtras); 339 340 try (Cursor cr = mDataLayer.fetchAllMedia(queryArgs)) { 341 assertThat(cr.getCount()).isEqualTo(1); 342 343 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 344 } 345 } 346 347 @Test testFetchMediaMimeTypeAndSizeFilter()348 public void testFetchMediaMimeTypeAndSizeFilter() { 349 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 350 351 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, IMAGE_MIME_TYPE, 352 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 353 /* isFavorite */ false); 354 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE, 355 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 356 /* isFavorite */ false); 357 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumId */ null, VIDEO_MIME_TYPE, 358 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 359 360 final Bundle queryArgs = buildQueryArgs(VIDEO_MIME_TYPE, SIZE_BYTES - 1); 361 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 362 mDataLayer.initMediaData(syncRequestExtras); 363 364 try (Cursor cr = mDataLayer.fetchAllMedia(queryArgs)) { 365 assertThat(cr.getCount()).isEqualTo(1); 366 367 assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 368 } 369 } 370 371 @Test testFetchMediaLocalOnly()372 public void testFetchMediaLocalOnly() { 373 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 374 375 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1); 376 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1); 377 378 Bundle queryArgs = buildDefaultQueryArgs(); 379 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 380 mDataLayer.initMediaData(syncRequestExtras); 381 382 // Verify that we only see local content 383 try (Cursor cr = mDataLayer.fetchLocalMedia(queryArgs)) { 384 assertThat(cr.getCount()).isEqualTo(1); 385 386 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 387 } 388 389 // Verify that we see cloud content 390 try (Cursor cr = mDataLayer.fetchAllMedia(queryArgs)) { 391 assertThat(cr.getCount()).isEqualTo(2); 392 393 assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 394 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 395 } 396 } 397 398 @Test testFetchAlbumMedia()399 public void testFetchAlbumMedia() { 400 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 401 402 mLocalMediaGenerator.createAlbum(ALBUM_ID_1); 403 mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_2); 404 405 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, ALBUM_ID_1, IMAGE_MIME_TYPE, 406 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 407 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_2, VIDEO_MIME_TYPE, 408 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 409 addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, /* albumId */ null, VIDEO_MIME_TYPE, 410 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true); 411 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumdId */ null, IMAGE_MIME_TYPE, 412 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true); 413 414 final Bundle defaultQueryArgs = buildDefaultQueryArgs(); 415 416 mDataLayer.initMediaData(buildDefaultSyncRequestExtras()); 417 try (Cursor cr = mDataLayer.fetchAllAlbums(defaultQueryArgs)) { 418 assertThat(cr.getCount()).isEqualTo(4); 419 420 // Most recent media item marked as favorite will be the cover of the Favorites album. 421 // In this scenario, Favorites album cover was generated with cloud authority, so the 422 // Favorites album authority should be cloud provider authority. Similarly, the most 423 // recent video was generated with local authority, so the Videos album authority should 424 // be local provider authority. 425 assertAlbumCursor(cr, ALBUM_ID_FAVORITES, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 426 assertAlbumCursor(cr, ALBUM_ID_VIDEOS, LOCAL_PROVIDER_AUTHORITY); 427 assertAlbumCursor(cr, ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY); 428 assertAlbumCursor(cr, ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 429 } 430 431 try (Cursor cr = mDataLayer.fetchAllMedia(defaultQueryArgs)) { 432 assertThat(cr.getCount()).isEqualTo(4); 433 434 assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 435 assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY); 436 assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 437 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 438 } 439 440 final Bundle localAlbumQueryArgs = buildQueryArgs(ALBUM_ID_1, 441 LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT); 442 mDataLayer.initMediaData(buildSyncRequestExtras(ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY)); 443 try (Cursor cr = mDataLayer.fetchAllMedia(localAlbumQueryArgs)) { 444 assertWithMessage("Local album count").that(cr.getCount()).isEqualTo(1); 445 446 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 447 } 448 449 final Bundle cloudAlbumQueryArgs = buildQueryArgs(ALBUM_ID_2, 450 CLOUD_PRIMARY_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT); 451 mDataLayer.initMediaData( 452 buildSyncRequestExtras(ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY)); 453 try (Cursor cr = mDataLayer.fetchAllMedia(cloudAlbumQueryArgs)) { 454 assertWithMessage("Cloud album count").that(cr.getCount()).isEqualTo(1); 455 456 assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 457 } 458 459 final Bundle favoriteAlbumQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES, 460 LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT); 461 mDataLayer.initMediaData(buildDefaultSyncRequestExtras()); 462 try (Cursor cr = mDataLayer.fetchAllMedia(favoriteAlbumQueryArgs)) { 463 assertWithMessage("Favorite album count").that(cr.getCount()).isEqualTo(2); 464 465 assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 466 assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY); 467 } 468 } 469 470 @Test testFetchAlbumMediaMimeTypeFilter()471 public void testFetchAlbumMediaMimeTypeFilter() { 472 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 473 474 mLocalMediaGenerator.createAlbum(ALBUM_ID_1); 475 mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_2); 476 477 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, ALBUM_ID_1, IMAGE_MIME_TYPE, 478 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 479 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_2, VIDEO_MIME_TYPE, 480 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 481 addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, ALBUM_ID_1, VIDEO_MIME_TYPE, 482 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 483 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, ALBUM_ID_2, IMAGE_MIME_TYPE, 484 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 485 486 final Bundle mimeTypeQueryArgs = buildQueryArgs(IMAGE_MIME_TYPE, SIZE_BYTES_DEFAULT); 487 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 488 mDataLayer.initMediaData(syncRequestExtras); 489 490 try (Cursor cr = mDataLayer.fetchAllAlbums(mimeTypeQueryArgs)) { 491 assertThat(cr.getCount()).isEqualTo(3); 492 493 // Favorites album will be always visible 494 assertAlbumCursor(cr, ALBUM_ID_FAVORITES, LOCAL_PROVIDER_AUTHORITY); 495 assertAlbumCursor(cr, ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY); 496 assertAlbumCursor(cr, ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 497 } 498 499 final Bundle localAlbumAndMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_1, 500 LOCAL_PROVIDER_AUTHORITY, IMAGE_MIME_TYPE, SIZE_BYTES_DEFAULT); 501 mDataLayer.initMediaData(buildSyncRequestExtras(ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY)); 502 try (Cursor cr = mDataLayer.fetchAllMedia(localAlbumAndMimeTypeQueryArgs)) { 503 assertWithMessage("Local album count").that(cr.getCount()).isEqualTo(1); 504 505 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 506 } 507 508 final Bundle cloudAlbumAndMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_2, 509 CLOUD_PRIMARY_PROVIDER_AUTHORITY, IMAGE_MIME_TYPE, SIZE_BYTES_DEFAULT); 510 mDataLayer.initMediaData( 511 buildSyncRequestExtras(ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY)); 512 try (Cursor cr = mDataLayer.fetchAllMedia(cloudAlbumAndMimeTypeQueryArgs)) { 513 assertWithMessage("Cloud album count").that(cr.getCount()).isEqualTo(1); 514 515 assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 516 } 517 } 518 519 @Test testFetchAlbumMediaSizeFilter()520 public void testFetchAlbumMediaSizeFilter() { 521 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 522 523 mLocalMediaGenerator.createAlbum(ALBUM_ID_1); 524 mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_2); 525 526 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, ALBUM_ID_1, IMAGE_MIME_TYPE, 527 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 528 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_2, VIDEO_MIME_TYPE, 529 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 530 /* isFavorite */ false); 531 addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, ALBUM_ID_1, VIDEO_MIME_TYPE, 532 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 533 /* isFavorite */ false); 534 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, ALBUM_ID_2, IMAGE_MIME_TYPE, 535 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 536 537 final Bundle sizeQueryArgs = buildQueryArgs(MIME_TYPE_DEFAULT, SIZE_BYTES - 1); 538 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 539 mDataLayer.initMediaData(syncRequestExtras); 540 541 try (Cursor cr = mDataLayer.fetchAllAlbums(sizeQueryArgs)) { 542 assertThat(cr.getCount()).isEqualTo(4); 543 544 // Favorites album will be always visible 545 assertAlbumCursor(cr, ALBUM_ID_FAVORITES, LOCAL_PROVIDER_AUTHORITY); 546 assertAlbumCursor(cr, ALBUM_ID_VIDEOS, LOCAL_PROVIDER_AUTHORITY); 547 assertAlbumCursor(cr, ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY); 548 assertAlbumCursor(cr, ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 549 } 550 551 final Bundle localAlbumAndSizeQueryArgs = buildQueryArgs(ALBUM_ID_1, 552 LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES -1); 553 mDataLayer.initMediaData(buildSyncRequestExtras(ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY)); 554 try (Cursor cr = mDataLayer.fetchAllMedia(localAlbumAndSizeQueryArgs)) { 555 assertWithMessage("Local album count").that(cr.getCount()).isEqualTo(1); 556 557 assertCursor(cr, LOCAL_ID_2, LOCAL_PROVIDER_AUTHORITY); 558 } 559 560 final Bundle cloudAlbumAndSizeQueryArgs = buildQueryArgs(ALBUM_ID_2, 561 CLOUD_PRIMARY_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES - 1); 562 mDataLayer.initMediaData( 563 buildSyncRequestExtras(ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY)); 564 try (Cursor cr = mDataLayer.fetchAllMedia(cloudAlbumAndSizeQueryArgs)) { 565 assertWithMessage("Cloud album count").that(cr.getCount()).isEqualTo(1); 566 567 assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 568 } 569 } 570 571 @Test testFetchAlbumMediaMimeTypeAndSizeFilter()572 public void testFetchAlbumMediaMimeTypeAndSizeFilter() { 573 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 574 575 mLocalMediaGenerator.createAlbum(ALBUM_ID_1); 576 mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_2); 577 578 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, ALBUM_ID_1, VIDEO_MIME_TYPE, 579 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 580 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_2, VIDEO_MIME_TYPE, 581 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 582 /* isFavorite */ false); 583 addMedia(mLocalMediaGenerator, LOCAL_ONLY_2, ALBUM_ID_1, VIDEO_MIME_TYPE, 584 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES - 1, 585 /* isFavorite */ false); 586 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, ALBUM_ID_2, VIDEO_MIME_TYPE, 587 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 588 589 final Bundle mimeTypeAndSizeQueryArgs = buildQueryArgs(VIDEO_MIME_TYPE, SIZE_BYTES -1); 590 final PickerSyncRequestExtras syncRequestExtras = buildDefaultSyncRequestExtras(); 591 mDataLayer.initMediaData(syncRequestExtras); 592 593 try (Cursor cr = mDataLayer.fetchAllAlbums(mimeTypeAndSizeQueryArgs)) { 594 assertWithMessage("Merged and Local album count").that(cr.getCount()).isEqualTo(4); 595 596 // Most recent video will be the cover of the Videos album. In this scenario, Videos 597 // album cover was generated with cloud authority, so the Videos album authority should 598 // be cloud provider authority. 599 // Favorites album will always be displayed. 600 assertAlbumCursor(cr, ALBUM_ID_FAVORITES, LOCAL_PROVIDER_AUTHORITY); 601 assertAlbumCursor(cr, ALBUM_ID_VIDEOS, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 602 assertAlbumCursor(cr, ALBUM_ID_1, LOCAL_PROVIDER_AUTHORITY); 603 assertAlbumCursor(cr, ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 604 } 605 606 final Bundle cloudAlbumAndMimeTypeQueryArgs = buildQueryArgs(ALBUM_ID_2, 607 CLOUD_PRIMARY_PROVIDER_AUTHORITY, VIDEO_MIME_TYPE, SIZE_BYTES - 1); 608 final PickerSyncRequestExtras cloudSyncRequestExtras = 609 buildSyncRequestExtras(ALBUM_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 610 mDataLayer.initMediaData(cloudSyncRequestExtras); 611 try (Cursor cr = mDataLayer.fetchAllMedia(cloudAlbumAndMimeTypeQueryArgs)) { 612 assertWithMessage("Cloud album count").that(cr.getCount()).isEqualTo(1); 613 614 assertCursor(cr, CLOUD_ID_1, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 615 } 616 } 617 618 @Test testFetchAlbumMediaLocalOnly()619 public void testFetchAlbumMediaLocalOnly() { 620 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 621 622 // Create a cloud album and add one cloud only item 623 mCloudPrimaryMediaGenerator.createAlbum(ALBUM_ID_1); 624 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_1, ALBUM_ID_1, VIDEO_MIME_TYPE, 625 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ false); 626 627 // Add one local only and one cloud only item and mark them favorite 628 addMedia(mLocalMediaGenerator, LOCAL_ONLY_1, /* albumId */ null, VIDEO_MIME_TYPE, 629 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true); 630 addMedia(mCloudPrimaryMediaGenerator, CLOUD_ONLY_2, /* albumdId */ null, IMAGE_MIME_TYPE, 631 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_NONE, SIZE_BYTES, /* isFavorite */ true); 632 633 // Album Info: 634 // Album_ID_1 - Cloud Album - 1 Video File 635 // Videos - Merged Album - 2 Video Files (1 local + 1 cloud) 636 // Favorites - Merged Album - 2 files (1 local + 1 cloud) 637 638 final Bundle defaultQueryArgs = buildDefaultQueryArgs(); 639 mDataLayer.initMediaData(buildDefaultSyncRequestExtras()); 640 // Verify that we see both local and cloud albums 641 try (Cursor cr = mDataLayer.fetchAllAlbums(defaultQueryArgs)) { 642 // Favorites and Videos merged albums will be always visible 643 assertThat(cr.getCount()).isEqualTo(3); 644 } 645 646 // Verify that we only see local albums with isLocalOnly=true 647 try (Cursor cr = mDataLayer.fetchLocalAlbums(defaultQueryArgs)) { 648 assertThat(cr.getCount()).isEqualTo(2); 649 650 cr.moveToNext(); 651 assertThat(cr.getString(cr.getColumnIndex(AlbumColumns.ID))) 652 .isEqualTo(ALBUM_ID_FAVORITES); 653 cr.moveToNext(); 654 assertThat(cr.getString(cr.getColumnIndex(AlbumColumns.ID))) 655 .isEqualTo(ALBUM_ID_VIDEOS); 656 } 657 658 final Bundle favoriteAlbumQueryArgs = buildQueryArgs(ALBUM_ID_FAVORITES, 659 LOCAL_PROVIDER_AUTHORITY, MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT); 660 661 try (Cursor cr = mDataLayer.fetchLocalMedia(favoriteAlbumQueryArgs)) { 662 assertWithMessage("Favorite album count").that(cr.getCount()).isEqualTo(1); 663 664 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 665 } 666 667 // Verify that we get cloud content in Album Media when queried with localOnly=false 668 try (Cursor cr = mDataLayer.fetchAllMedia(favoriteAlbumQueryArgs)) { 669 assertWithMessage("Favorite album count").that(cr.getCount()).isEqualTo(2); 670 671 assertCursor(cr, CLOUD_ID_2, CLOUD_PRIMARY_PROVIDER_AUTHORITY); 672 assertCursor(cr, LOCAL_ID_1, LOCAL_PROVIDER_AUTHORITY); 673 } 674 } 675 676 @Test testFetchCloudAccountInfo()677 public void testFetchCloudAccountInfo() { 678 // Cloud provider is not set so cloud account info is null 679 assertThat(mDataLayer.fetchCloudAccountInfo()).isNull(); 680 681 // Set cloud provider 682 mFacade.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 683 684 // Still null since cloud provider doesn't return account info yet 685 assertThat(mDataLayer.fetchCloudAccountInfo()).isNull(); 686 687 // Fake cloud provider cloud account info 688 final String expectedName = "bar"; 689 final Intent expectedIntent = new Intent("foo"); 690 mCloudPrimaryMediaGenerator.setAccountInfo(expectedName, expectedIntent); 691 692 // Verify account info 693 final PickerDataLayer.AccountInfo info = mDataLayer.fetchCloudAccountInfo(); 694 assertThat(info).isNotNull(); 695 assertThat(info.accountName).isEqualTo(expectedName); 696 assertThat(info.accountConfigurationIntent).isEqualTo(expectedIntent); 697 } 698 699 @Test testInitMediaDataInvalidData()700 public void testInitMediaDataInvalidData() { 701 final Bundle syncExtrasBundle = new Bundle(); 702 syncExtrasBundle.putString(MediaStore.EXTRA_ALBUM_ID, "NotMergedAlbum"); 703 syncExtrasBundle.putString(MediaStore.EXTRA_ALBUM_AUTHORITY, "NotLocalAuthority"); 704 syncExtrasBundle.putBoolean(MediaStore.EXTRA_LOCAL_ONLY, true); 705 final PickerSyncRequestExtras syncExtras = 706 PickerSyncRequestExtras.fromBundle(syncExtrasBundle); 707 708 assertThrows(IllegalStateException.class, 709 () -> mDataLayer.initMediaData(syncExtras)); 710 } 711 712 @Test testCloudPackageAllowlistListenerRemovesActiveThatIsNowInvalid()713 public void testCloudPackageAllowlistListenerRemovesActiveThatIsNowInvalid() { 714 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 715 assertThat(mController.getCurrentCloudProviderInfo().packageName).isEqualTo(PACKAGE_NAME); 716 717 // Simulate a DeviceConfig change where the Allowlist is set to empty. 718 mConfigStore.setAllowedCloudProviderPackages(new String[] {}); 719 720 721 // The listener uses the ForegroundThread to run the listener, so wait for the 722 // ForegroundThread to complete. 723 ForegroundThread.waitForIdle(); 724 725 assertThat(mController.getCurrentCloudProviderInfo()).isEqualTo(CloudProviderInfo.EMPTY); 726 } 727 728 @Test testCloudPackageAllowlistListenerDoesNotChangeAllowedProvider()729 public void testCloudPackageAllowlistListenerDoesNotChangeAllowedProvider() { 730 mController.setCloudProvider(CLOUD_PRIMARY_PROVIDER_AUTHORITY); 731 assertThat(mController.getCurrentCloudProviderInfo().packageName).isEqualTo(PACKAGE_NAME); 732 733 // Simulate a DeviceConfig change where the Allowlist adds a new provider, but the current 734 // provider is still permitted. 735 final String newlyAddedProviderPackage = "com.hooli.super.awesome.cloud.provider"; 736 mConfigStore.setAllowedCloudProviderPackages( 737 new String[] {PACKAGE_NAME, newlyAddedProviderPackage}); 738 739 // The listener uses the ForegroundThread to run the listener, so wait for the 740 // ForegroundThread to complete. 741 ForegroundThread.waitForIdle(); 742 743 // Ensure nothing was changed. 744 assertThat(mController.getCurrentCloudProviderInfo().packageName).isEqualTo(PACKAGE_NAME); 745 } 746 waitForIdle()747 private static void waitForIdle() { 748 final CountDownLatch latch = new CountDownLatch(1); 749 BackgroundThread.getExecutor().execute(() -> { 750 latch.countDown(); 751 }); 752 try { 753 latch.await(30, TimeUnit.SECONDS); 754 } catch (InterruptedException e) { 755 throw new IllegalStateException(e); 756 } 757 758 } 759 buildDefaultQueryArgs()760 private static Bundle buildDefaultQueryArgs() { 761 return buildQueryArgs(MIME_TYPE_DEFAULT, SIZE_BYTES_DEFAULT); 762 } 763 buildQueryArgs(String mimeType, long sizeBytes)764 private static Bundle buildQueryArgs(String mimeType, long sizeBytes) { 765 final Bundle queryArgs = new Bundle(); 766 767 if (mimeType != null) { 768 queryArgs.putStringArray(MediaStore.QUERY_ARG_MIME_TYPE, new String[]{mimeType}); 769 } 770 queryArgs.putLong(MediaStore.QUERY_ARG_SIZE_BYTES, sizeBytes); 771 772 return queryArgs; 773 } 774 buildQueryArgs(String albumId, String albumAuthority, String mimeType, long sizeBytes)775 private static Bundle buildQueryArgs(String albumId, String albumAuthority, String mimeType, 776 long sizeBytes) { 777 final Bundle queryArgs = buildQueryArgs(mimeType, sizeBytes); 778 779 queryArgs.putString(MediaStore.QUERY_ARG_ALBUM_ID, albumId); 780 queryArgs.putString(MediaStore.QUERY_ARG_ALBUM_AUTHORITY, albumAuthority); 781 782 return queryArgs; 783 } 784 785 @NonNull buildDefaultSyncRequestExtras()786 private static PickerSyncRequestExtras buildDefaultSyncRequestExtras() { 787 return PickerSyncRequestExtras.fromBundle(buildDefaultSyncRequestBundle()); 788 } 789 790 @NonNull buildSyncRequestExtras(@onNull String albumId, @NonNull String albumAuthority)791 private static PickerSyncRequestExtras buildSyncRequestExtras(@NonNull String albumId, 792 @NonNull String albumAuthority) { 793 final Bundle syncRequestExtras = buildDefaultSyncRequestBundle(); 794 syncRequestExtras.putString(MediaStore.EXTRA_ALBUM_ID, albumId); 795 syncRequestExtras.putString(MediaStore.EXTRA_ALBUM_AUTHORITY, albumAuthority); 796 797 return PickerSyncRequestExtras 798 .fromBundle(syncRequestExtras); 799 } 800 801 @NonNull buildDefaultSyncRequestBundle()802 private static Bundle buildDefaultSyncRequestBundle() { 803 final Bundle syncRequestExtras = new Bundle(); 804 syncRequestExtras.putBoolean(MediaStore.EXTRA_LOCAL_ONLY, false); 805 806 return syncRequestExtras; 807 } 808 addMedia(MediaGenerator generator, Pair<String, String> media)809 private static void addMedia(MediaGenerator generator, Pair<String, String> media) { 810 generator.addMedia(media.first, media.second); 811 } 812 addMedia(MediaGenerator generator, Pair<String, String> media, String albumId, String mimeType, int standardMimeTypeExtension, long sizeBytes, boolean isFavorite)813 private static void addMedia(MediaGenerator generator, Pair<String, String> media, 814 String albumId, String mimeType, int standardMimeTypeExtension, long sizeBytes, 815 boolean isFavorite) { 816 generator.addMedia(media.first, media.second, albumId, mimeType, 817 standardMimeTypeExtension, sizeBytes, isFavorite); 818 } 819 deleteMedia(MediaGenerator generator, Pair<String, String> media)820 private static void deleteMedia(MediaGenerator generator, Pair<String, String> media) { 821 generator.deleteMedia(media.first, media.second); 822 } 823 queryMedia()824 private Cursor queryMedia() { 825 return mFacade.queryMediaForUi( 826 new PickerDbFacade.QueryFilterBuilder(1000).build()); 827 } 828 assertEmptyCursor()829 private void assertEmptyCursor() { 830 try (Cursor cr = queryMedia()) { 831 assertThat(cr.getCount()).isEqualTo(0); 832 } 833 } 834 assertAlbumCursor(Cursor cursor, String id, String expectedAuthority)835 private static void assertAlbumCursor(Cursor cursor, String id, String expectedAuthority) { 836 cursor.moveToNext(); 837 assertThat(cursor.getString(cursor.getColumnIndex(AlbumColumns.ID))) 838 .isEqualTo(id); 839 final int authorityIdx = cursor.getColumnIndex(AlbumColumns.AUTHORITY); 840 String authority = null; 841 if (authorityIdx >= 0) { 842 // Cursor from picker db has authority as a column 843 authority = cursor.getString(authorityIdx); 844 } 845 if (authority == null) { 846 // Cursor from provider directly doesn't have an authority column but will 847 // have the authority set as an extra 848 final Bundle bundle = cursor.getExtras(); 849 authority = bundle.getString(MediaStore.EXTRA_CLOUD_PROVIDER); 850 } 851 852 assertThat(authority).isEqualTo(expectedAuthority); 853 } 854 assertCursor(Cursor cursor, String id, String expectedAuthority)855 private static void assertCursor(Cursor cursor, String id, String expectedAuthority) { 856 cursor.moveToNext(); 857 assertThat(cursor.getString(cursor.getColumnIndex(MediaColumns.ID))) 858 .isEqualTo(id); 859 assertThat(cursor.getString(cursor.getColumnIndex(MediaColumns.AUTHORITY))) 860 .isEqualTo(expectedAuthority); 861 } 862 } 863