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.data; 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.photopicker.util.PickerDbTestUtils.ALBUM_ID; 23 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.CLOUD_ID; 24 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.CLOUD_ID_1; 25 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.CLOUD_ID_2; 26 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.CLOUD_ID_3; 27 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.CLOUD_ID_4; 28 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.CLOUD_PROVIDER; 29 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.DATE_TAKEN_MS; 30 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.GENERATION_MODIFIED; 31 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.GIF_IMAGE_MIME_TYPE; 32 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.IMAGE_MIME_TYPES_QUERY; 33 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.JPEG_IMAGE_MIME_TYPE; 34 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.LOCAL_ID; 35 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.LOCAL_ID_1; 36 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.LOCAL_ID_2; 37 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.LOCAL_ID_3; 38 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.LOCAL_ID_4; 39 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.LOCAL_PROVIDER; 40 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.M4V_VIDEO_MIME_TYPE; 41 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.MP4_VIDEO_MIME_TYPE; 42 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.MPEG_VIDEO_MIME_TYPE; 43 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.PNG_IMAGE_MIME_TYPE; 44 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.SIZE_BYTES; 45 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.STANDARD_MIME_TYPE_EXTENSION; 46 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.TEST_PACKAGE_NAME; 47 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.VIDEO_MIME_TYPES_QUERY; 48 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.WEBM_VIDEO_MIME_TYPE; 49 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertAddAlbumMediaOperation; 50 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertAddMediaOperation; 51 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertAllMediaCursor; 52 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertClearGrantsOperation; 53 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertCloudAlbumCursor; 54 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertCloudMediaCursor; 55 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertGrantsCursor; 56 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertInsertGrantsOperation; 57 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertMediaStoreCursor; 58 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertRemoveMediaOperation; 59 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertResetAlbumMediaOperation; 60 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertResetMediaOperation; 61 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.assertWriteOperation; 62 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.getAlbumMediaCursor; 63 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.getCloudMediaCursor; 64 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.getDeletedMediaCursor; 65 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.getLocalMediaCursor; 66 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.getMediaCursor; 67 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.getMediaGrantsCursor; 68 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.queryAlbumMedia; 69 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.queryGrants; 70 import static com.android.providers.media.photopicker.util.PickerDbTestUtils.queryMediaAll; 71 72 import static com.google.common.truth.Truth.assertWithMessage; 73 74 import static org.junit.Assert.assertThrows; 75 import static org.mockito.Mockito.doReturn; 76 import static org.mockito.MockitoAnnotations.initMocks; 77 78 import android.content.ContentValues; 79 import android.content.Context; 80 import android.database.Cursor; 81 import android.database.sqlite.SQLiteQueryBuilder; 82 import android.os.UserHandle; 83 import android.provider.CloudMediaProviderContract.MediaColumns; 84 import android.provider.Column; 85 import android.provider.ExportedSince; 86 import android.provider.MediaStore.PickerMediaColumns; 87 88 import androidx.test.ext.junit.runners.AndroidJUnit4; 89 import androidx.test.platform.app.InstrumentationRegistry; 90 91 import com.android.providers.media.MediaGrants; 92 import com.android.providers.media.PickerUriResolver; 93 import com.android.providers.media.ProjectionHelper; 94 import com.android.providers.media.photopicker.sync.PickerSyncLockManager; 95 import com.android.providers.media.photopicker.sync.SyncTracker; 96 import com.android.providers.media.photopicker.sync.SyncTrackerRegistry; 97 98 import org.junit.After; 99 import org.junit.Before; 100 import org.junit.Test; 101 import org.junit.runner.RunWith; 102 import org.mockito.Mock; 103 104 import java.io.File; 105 import java.util.Collections; 106 import java.util.List; 107 import java.util.concurrent.CompletableFuture; 108 109 @RunWith(AndroidJUnit4.class) 110 public class PickerDbFacadeTest { 111 private PickerDbFacade mFacade; 112 private Context mContext; 113 private ProjectionHelper mProjectionHelper; 114 115 @Mock 116 private SyncTracker mMockLocalSyncTracker; 117 @Mock 118 private SyncTracker mMockCloudSyncTracker; 119 120 @Before setUp()121 public void setUp() { 122 initMocks(this); 123 mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 124 File dbPath = mContext.getDatabasePath(PickerDatabaseHelper.PICKER_DATABASE_NAME); 125 dbPath.delete(); 126 mFacade = new PickerDbFacade(mContext, new PickerSyncLockManager(), LOCAL_PROVIDER); 127 mFacade.setCloudProvider(CLOUD_PROVIDER); 128 mProjectionHelper = new ProjectionHelper(Column.class, ExportedSince.class); 129 130 131 // Inject mock trackers 132 SyncTrackerRegistry.setLocalSyncTracker(mMockLocalSyncTracker); 133 SyncTrackerRegistry.setCloudSyncTracker(mMockCloudSyncTracker); 134 } 135 136 @After tearDown()137 public void tearDown() { 138 if (mFacade != null) { 139 mFacade.setCloudProvider(null); 140 } 141 142 // Reset mock trackers 143 SyncTrackerRegistry.setLocalSyncTracker(new SyncTracker()); 144 SyncTrackerRegistry.setCloudSyncTracker(new SyncTracker()); 145 } 146 147 @Test testAddLocalOnlyMedia()148 public void testAddLocalOnlyMedia() throws Exception { 149 Cursor cursor1 = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS + 1); 150 Cursor cursor2 = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS + 2); 151 152 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor1, 1); 153 154 try (Cursor cr = queryMediaAll(mFacade)) { 155 assertWithMessage( 156 "Unexpected number of media after addMediaOperation with cursor1 " 157 + "on LOCAL_PROVIDER.") 158 .that(cr.getCount()).isEqualTo(1); 159 cr.moveToFirst(); 160 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS + 1); 161 } 162 163 // Test updating the same row 164 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor2, 1); 165 166 try (Cursor cr = queryMediaAll(mFacade)) { 167 assertWithMessage( 168 "Unexpected number of media after trying to update the same row with cursor2 " 169 + "on LOCAL_PROVIDER.") 170 .that(cr.getCount()).isEqualTo(1); 171 cr.moveToFirst(); 172 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS + 2); 173 } 174 } 175 176 @Test testAddCloudPlusLocal()177 public void testAddCloudPlusLocal() throws Exception { 178 Cursor cursor = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS); 179 180 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor, 1); 181 182 try (Cursor cr = queryMediaAll(mFacade)) { 183 assertWithMessage( 184 "Unexpected number of media after addMediaOperation on CLOUD_PROVIDER.") 185 .that(cr.getCount()).isEqualTo(1); 186 cr.moveToFirst(); 187 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS); 188 } 189 } 190 191 @Test testAddCloudOnly()192 public void testAddCloudOnly() throws Exception { 193 Cursor cursor1 = getCloudMediaCursor(CLOUD_ID, null, DATE_TAKEN_MS + 1); 194 Cursor cursor2 = getCloudMediaCursor(CLOUD_ID, null, DATE_TAKEN_MS + 2); 195 196 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor1, 1); 197 198 try (Cursor cr = queryMediaAll(mFacade)) { 199 assertWithMessage( 200 "Unexpected number of media after addMediaOperation with cursor1 on " 201 + "CLOUD_PROVIDER.") 202 .that(cr.getCount()).isEqualTo(1); 203 cr.moveToFirst(); 204 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS + 1); 205 } 206 207 // Test updating the same row 208 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor2, 1); 209 210 try (Cursor cr = queryMediaAll(mFacade)) { 211 assertWithMessage( 212 "Unexpected number of media after trying to update the same row with cursor2 " 213 + "on CLOUD_PROVIDER.") 214 .that(cr.getCount()).isEqualTo(1); 215 cr.moveToFirst(); 216 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS + 2); 217 } 218 } 219 220 @Test testAddLocalAndCloud_Dedupe()221 public void testAddLocalAndCloud_Dedupe() throws Exception { 222 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 223 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS + 1); 224 225 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 226 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 227 228 try (Cursor cr = queryMediaAll(mFacade)) { 229 assertWithMessage( 230 "Unexpected number of media after addMediaOperation with:\nlocalCursor having " 231 + "localId = " + LOCAL_ID + ", followed by\ncloudCursor having " 232 + "localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID) 233 .that(cr.getCount()).isEqualTo(1); 234 cr.moveToFirst(); 235 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 236 } 237 } 238 239 @Test testAddCloudAndLocal_Dedupe()240 public void testAddCloudAndLocal_Dedupe() throws Exception { 241 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS + 1); 242 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS); 243 244 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 245 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 246 247 try (Cursor cr = queryMediaAll(mFacade)) { 248 assertWithMessage( 249 "Unexpected number of media after addMediaOperation with:\ncloudCursor having " 250 + "localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID + ", followed by" 251 + "\ncloudCursor having localId = " + LOCAL_ID) 252 .that(cr.getCount()).isEqualTo(1); 253 cr.moveToFirst(); 254 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS + 1); 255 } 256 } 257 258 @Test testMediaSortOrder()259 public void testMediaSortOrder() { 260 final Cursor cursor1 = getLocalMediaCursor(LOCAL_ID_1, DATE_TAKEN_MS); 261 final Cursor cursor2 = getCloudMediaCursor(CLOUD_ID_1, null, DATE_TAKEN_MS); 262 final Cursor cursor3 = getLocalMediaCursor(LOCAL_ID_2, DATE_TAKEN_MS + 1); 263 264 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor1, 1); 265 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor2, 1); 266 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor3, 1); 267 268 try (Cursor cr = queryMediaAll(mFacade)) { 269 assertWithMessage( 270 "Unexpected number of media on queryMediaAll() after adding 2 " 271 + "localMediaCursor and 1 cloudMediaCursor to " 272 + LOCAL_PROVIDER + " and " + CLOUD_PROVIDER + " respectively.") 273 .that(cr.getCount()).isEqualTo(/* expected= */ 3); 274 275 cr.moveToFirst(); 276 // Latest items should show up first. 277 assertCloudMediaCursor(cr, LOCAL_ID_2, DATE_TAKEN_MS + 1); 278 279 cr.moveToNext(); 280 // If the date taken is the same for 2 or more items, they should be sorted in the order 281 // of their insertion in the database with the latest row inserted first. 282 assertCloudMediaCursor(cr, CLOUD_ID_1, DATE_TAKEN_MS); 283 284 cr.moveToNext(); 285 assertCloudMediaCursor(cr, LOCAL_ID_1, DATE_TAKEN_MS); 286 } 287 } 288 289 @Test testAddLocalAlbumMedia()290 public void testAddLocalAlbumMedia() { 291 Cursor cursor1 = getAlbumMediaCursor(LOCAL_ID, /* cloud id */ null, DATE_TAKEN_MS + 1); 292 Cursor cursor2 = getAlbumMediaCursor(LOCAL_ID, /* cloud id */ null, DATE_TAKEN_MS + 2); 293 294 assertAddAlbumMediaOperation(mFacade, LOCAL_PROVIDER, cursor1, 1, ALBUM_ID); 295 296 try (Cursor cr = queryAlbumMedia(mFacade, ALBUM_ID, true)) { 297 assertWithMessage( 298 "Unexpected number of albumMedia after adding albumMediaCursor having localId" 299 + " = " 300 + LOCAL_ID + " cloudId = " + null + " to " + LOCAL_PROVIDER) 301 .that(cr.getCount()).isEqualTo(1); 302 cr.moveToFirst(); 303 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS + 1); 304 } 305 306 // Test updating the same row. We always do a full sync for album media files. 307 assertResetAlbumMediaOperation(mFacade, LOCAL_PROVIDER, 1, ALBUM_ID); 308 assertAddAlbumMediaOperation(mFacade, LOCAL_PROVIDER, cursor2, 1, ALBUM_ID); 309 310 try (Cursor cr = queryAlbumMedia(mFacade, ALBUM_ID, true)) { 311 assertWithMessage( 312 "Unexpected number of albumMedia after resetting and updating the same row " 313 + "with albumMediaCursor having localId = " 314 + LOCAL_ID + " cloudId = " + null) 315 .that(cr.getCount()).isEqualTo(1); 316 cr.moveToFirst(); 317 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS + 2); 318 } 319 } 320 321 @Test testAddCloudAlbumMedia()322 public void testAddCloudAlbumMedia() { 323 Cursor cursor1 = getAlbumMediaCursor(/* local id */ null, CLOUD_ID, DATE_TAKEN_MS + 1); 324 Cursor cursor2 = getAlbumMediaCursor(/* local id */ null, CLOUD_ID, DATE_TAKEN_MS + 2); 325 326 assertAddAlbumMediaOperation(mFacade, CLOUD_PROVIDER, cursor1, 1, ALBUM_ID); 327 328 try (Cursor cr = queryAlbumMedia(mFacade, ALBUM_ID, false)) { 329 assertWithMessage( 330 "Unexpected number of albumMedia after adding albumMediaCursor having localId" 331 + " = " 332 + null + " cloudId = " + CLOUD_ID + " to " + CLOUD_PROVIDER) 333 .that(cr.getCount()).isEqualTo(1); 334 cr.moveToFirst(); 335 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS + 1); 336 } 337 338 // Test updating the same row. We always do a full sync for album media files. 339 assertResetAlbumMediaOperation(mFacade, CLOUD_PROVIDER, 1, ALBUM_ID); 340 assertAddAlbumMediaOperation(mFacade, CLOUD_PROVIDER, cursor2, 1, ALBUM_ID); 341 342 try (Cursor cr = queryAlbumMedia(mFacade, ALBUM_ID, false)) { 343 assertWithMessage( 344 "Unexpected number of albumMedia after resetting and updating the same row " 345 + "with albumMediaCursor having localId = " 346 + null + " cloudId = " + CLOUD_PROVIDER) 347 .that(cr.getCount()).isEqualTo(1); 348 cr.moveToFirst(); 349 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS + 2); 350 } 351 } 352 353 @Test testAddAndClearGrants()354 public void testAddAndClearGrants() { 355 Cursor cursor1 = getMediaGrantsCursor(LOCAL_ID); 356 357 // insert a grants. 358 assertInsertGrantsOperation(mFacade, cursor1, 1); 359 // verify the grants is present in the database. 360 try (Cursor cr = queryGrants(mFacade)) { 361 assertWithMessage( 362 "Unexpected number of grants ") 363 .that(cr.getCount()).isEqualTo(1); 364 cr.moveToFirst(); 365 assertGrantsCursor(cr, LOCAL_ID); 366 } 367 368 // clear all grants. 369 assertClearGrantsOperation(mFacade, 1, new String[]{TEST_PACKAGE_NAME}, 370 UserHandle.myUserId()); 371 // verify that the grants have been cleared. 372 try (Cursor cr = queryGrants(mFacade)) { 373 assertWithMessage( 374 "Unexpected number of grants ") 375 .that(cr.getCount()).isEqualTo(0); 376 } 377 } 378 379 @Test testAddWhereClausesForMediaGrantsTable()380 public void testAddWhereClausesForMediaGrantsTable() { 381 // set up 382 SQLiteQueryBuilder sqb = new SQLiteQueryBuilder(); 383 int testUserId = 1; 384 String[] testPackageNames = {"com.test.example"}; 385 386 // adding where clause 387 PickerDbFacade.addWhereClausesForMediaGrantsTable(sqb, testUserId, testPackageNames); 388 389 // verify where clauses have been added to the query. 390 String resultQuery = sqb.buildQuery(null, null, null, null, null, null); 391 392 assertWithMessage("Query should contain clause for userId.").that( 393 resultQuery.contains(String.format("%s = %d", MediaGrants.PACKAGE_USER_ID_COLUMN, 394 testUserId))).isEqualTo(true); 395 assertWithMessage("Query should contain clause for packageNames.") 396 .that(resultQuery.contains(String.format("%s IN (\"%s\")", 397 MediaGrants.OWNER_PACKAGE_NAME_COLUMN, 398 testPackageNames[0]))).isEqualTo( 399 true); 400 } 401 402 @Test testAddCloudAlbumMediaWhileCloudSyncIsRunning()403 public void testAddCloudAlbumMediaWhileCloudSyncIsRunning() { 404 405 406 doReturn(Collections.singletonList(new CompletableFuture<>())) 407 .when(mMockCloudSyncTracker) 408 .pendingSyncFutures(); 409 410 Cursor cursor1 = getAlbumMediaCursor(/* local id */ null, CLOUD_ID, DATE_TAKEN_MS + 1); 411 412 assertAddAlbumMediaOperation(mFacade, CLOUD_PROVIDER, cursor1, 1, ALBUM_ID); 413 414 try (Cursor cr = queryAlbumMedia(mFacade, ALBUM_ID, false)) { 415 assertWithMessage( 416 "Unexpected number of albumMedia after adding albumMediaCursor having localId" 417 + " = " 418 + null + " cloudId = " + CLOUD_ID + " to " + CLOUD_PROVIDER) 419 .that(cr.getCount()).isEqualTo(1); 420 cr.moveToFirst(); 421 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS + 1); 422 } 423 424 // These files should also be in the media table since we're pretending that 425 // we have a cloud sync running. 426 try (Cursor cr = queryMediaAll(mFacade)) { 427 assertWithMessage( 428 "Unexpected number of media on querying all media with cloud sync running.") 429 .that(cr.getCount()).isEqualTo(1); 430 cr.moveToFirst(); 431 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS + 1); 432 } 433 } 434 435 @Test testAddCloudAlbumMediaAvailableOnDevice()436 public void testAddCloudAlbumMediaAvailableOnDevice() { 437 // Add local row for a media item in media table. 438 final Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 439 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 440 441 // Attempt to insert a media item available locally and on cloud in album_media table. 442 final Cursor cloudCursor = 443 getAlbumMediaCursor(LOCAL_ID, CLOUD_ID, DATE_TAKEN_MS + 1); 444 assertAddAlbumMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1, ALBUM_ID); 445 446 // Assert that preference was given to the local media item over cloud media item at the 447 // time of insertion in album_media table. 448 try (Cursor albumCursor = queryAlbumMedia(mFacade, ALBUM_ID, false)) { 449 assertWithMessage( 450 "Unexpected number of albumMedia on querying " + ALBUM_ID) 451 .that(albumCursor.getCount()).isEqualTo(1); 452 albumCursor.moveToFirst(); 453 assertCloudMediaCursor(albumCursor, LOCAL_ID, DATE_TAKEN_MS); 454 } 455 } 456 457 @Test testAddCloudAlbumMediaDeletedFromDevice()458 public void testAddCloudAlbumMediaDeletedFromDevice() { 459 // Attempt to insert a media item deleted from device and available on cloud in the 460 // album_media table. 461 final Cursor cloudCursor = 462 getAlbumMediaCursor(LOCAL_ID, CLOUD_ID, DATE_TAKEN_MS); 463 assertAddAlbumMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1, ALBUM_ID); 464 465 // Assert that cloud media metadata was inserted in the database as local_id points to a 466 // deleted item. 467 try (Cursor albumCursor = queryAlbumMedia(mFacade, ALBUM_ID, false)) { 468 assertWithMessage( 469 "Unexpected number of albumMedia on querying " + ALBUM_ID) 470 .that(albumCursor.getCount()).isEqualTo(1); 471 albumCursor.moveToFirst(); 472 assertCloudMediaCursor(albumCursor, CLOUD_ID, DATE_TAKEN_MS); 473 } 474 } 475 476 @Test testAlbumMediaSortOrder()477 public void testAlbumMediaSortOrder() { 478 final Cursor cursor1 = getAlbumMediaCursor(null, CLOUD_ID_1, DATE_TAKEN_MS); 479 final Cursor cursor2 = getAlbumMediaCursor(LOCAL_ID_1, null, DATE_TAKEN_MS); 480 final Cursor cursor3 = getAlbumMediaCursor(null, CLOUD_ID_2, DATE_TAKEN_MS + 1); 481 482 assertAddAlbumMediaOperation(mFacade, CLOUD_PROVIDER, cursor1, 1, ALBUM_ID); 483 assertAddAlbumMediaOperation(mFacade, LOCAL_PROVIDER, cursor2, 1, ALBUM_ID); 484 assertAddAlbumMediaOperation(mFacade, CLOUD_PROVIDER, cursor3, 1, ALBUM_ID); 485 486 try (Cursor cr = queryAlbumMedia(mFacade, ALBUM_ID, false)) { 487 assertWithMessage( 488 "Unexpected number of media on queryMediaAll() after adding 2 " 489 + "cloudAlbumMediaCursor and 1 localAlbumMediaCursor to " 490 + CLOUD_PROVIDER + " and " + LOCAL_PROVIDER + " respectively.") 491 .that(cr.getCount()).isEqualTo(/* expected= */ 3); 492 493 cr.moveToFirst(); 494 // Latest items should show up first. 495 assertCloudMediaCursor(cr, CLOUD_ID_2, DATE_TAKEN_MS + 1); 496 497 cr.moveToNext(); 498 // If the date taken is the same for 2 or more items, they should be sorted in the order 499 // of their insertion in the database with the latest row inserted first. 500 assertCloudMediaCursor(cr, LOCAL_ID_1, DATE_TAKEN_MS); 501 502 cr.moveToNext(); 503 assertCloudMediaCursor(cr, CLOUD_ID_1, DATE_TAKEN_MS); 504 } 505 } 506 507 @Test testRemoveLocal()508 public void testRemoveLocal() throws Exception { 509 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 510 511 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 512 513 try (Cursor cr = queryMediaAll(mFacade)) { 514 assertWithMessage( 515 "Unexpected number of media after addMediaOperation with local media cursor " 516 + "localCursor.") 517 .that(cr.getCount()).isEqualTo(1); 518 } 519 520 assertRemoveMediaOperation(mFacade, LOCAL_PROVIDER, getDeletedMediaCursor(LOCAL_ID), 1); 521 522 try (Cursor cr = queryMediaAll(mFacade)) { 523 assertWithMessage( 524 "Unexpected number of media after removeMediaOperation on local provider.") 525 .that(cr.getCount()).isEqualTo(0); 526 } 527 } 528 529 @Test testRemoveLocal_promote()530 public void testRemoveLocal_promote() throws Exception { 531 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 532 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS); 533 534 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 535 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 536 537 try (Cursor cr = queryMediaAll(mFacade)) { 538 assertWithMessage( 539 "Unexpected number of media after addMediaOperation with one localCursor and " 540 + "one cloudCursor where " 541 + "\nlocalCursor has localId = " + LOCAL_ID 542 + "\ncloudCursor has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID) 543 .that(cr.getCount()).isEqualTo(1); 544 cr.moveToFirst(); 545 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 546 } 547 548 assertRemoveMediaOperation(mFacade, LOCAL_PROVIDER, getDeletedMediaCursor(LOCAL_ID), 1); 549 550 try (Cursor cr = queryMediaAll(mFacade)) { 551 assertWithMessage( 552 "Unexpected number of media after removeMediaOperation on local provider.") 553 .that(cr.getCount()).isEqualTo(1); 554 cr.moveToFirst(); 555 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS); 556 } 557 } 558 559 @Test testRemoveCloud()560 public void testRemoveCloud() throws Exception { 561 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS); 562 563 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 564 565 try (Cursor cr = queryMediaAll(mFacade)) { 566 assertWithMessage( 567 "Unexpected number of media after addMediaOperation with cloud media cursor " 568 + "cloudCursor.") 569 .that(cr.getCount()).isEqualTo(1); 570 } 571 572 assertRemoveMediaOperation(mFacade, CLOUD_PROVIDER, getDeletedMediaCursor(CLOUD_ID), 1); 573 574 try (Cursor cr = queryMediaAll(mFacade)) { 575 assertWithMessage( 576 "Unexpected number of media after removeMediaOperation on cloud provider.") 577 .that(cr.getCount()).isEqualTo(0); 578 } 579 } 580 581 @Test testRemoveCloud_promote()582 public void testRemoveCloud_promote() throws Exception { 583 Cursor cloudCursor1 = getCloudMediaCursor(CLOUD_ID + "1", LOCAL_ID, DATE_TAKEN_MS + 1); 584 Cursor cloudCursor2 = getCloudMediaCursor(CLOUD_ID + "2", LOCAL_ID, DATE_TAKEN_MS + 2); 585 586 try (PickerDbFacade.DbWriteOperation operation = 587 mFacade.beginAddMediaOperation(CLOUD_PROVIDER)) { 588 assertWriteOperation(operation, cloudCursor1, 1); 589 assertWriteOperation(operation, cloudCursor2, 1); 590 operation.setSuccess(); 591 } 592 593 try (Cursor cr = queryMediaAll(mFacade)) { 594 assertWithMessage( 595 "Unexpected number of media after addMediaOperation with two cloudCursor where " 596 + "\ncloudCursor1 has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID 597 + "1" 598 + "\ncloudCursor2 has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID 599 + "2" 600 ) 601 .that(cr.getCount()).isEqualTo(1); 602 cr.moveToFirst(); 603 assertCloudMediaCursor(cr, CLOUD_ID + "1", DATE_TAKEN_MS + 1); 604 } 605 606 assertRemoveMediaOperation(mFacade, CLOUD_PROVIDER, 607 getDeletedMediaCursor(CLOUD_ID + "1"), 1); 608 609 try (Cursor cr = queryMediaAll(mFacade)) { 610 assertWithMessage( 611 "Unexpected number of media after removeMediaOperation on cloud provider.") 612 .that(cr.getCount()).isEqualTo(1); 613 cr.moveToFirst(); 614 assertCloudMediaCursor(cr, CLOUD_ID + "2", DATE_TAKEN_MS + 2); 615 } 616 } 617 618 @Test testRemoveHidden()619 public void testRemoveHidden() throws Exception { 620 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 621 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS); 622 623 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 624 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 625 626 try (Cursor cr = queryMediaAll(mFacade)) { 627 assertWithMessage( 628 "Unexpected number of media after addMediaOperation with one localCursor and " 629 + "one cloudCursor where " 630 + "\nlocalCursor has localId = " + LOCAL_ID 631 + "\ncloudCursor has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID) 632 .that(cr.getCount()).isEqualTo(1); 633 cr.moveToFirst(); 634 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 635 } 636 637 assertRemoveMediaOperation(mFacade, CLOUD_PROVIDER, getDeletedMediaCursor(CLOUD_ID), 1); 638 639 try (Cursor cr = queryMediaAll(mFacade)) { 640 assertWithMessage( 641 "Unexpected number of media after removeMediaOperation on cloud provider.") 642 .that(cr.getCount()).isEqualTo(1); 643 cr.moveToFirst(); 644 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 645 } 646 } 647 648 649 @Test testLocalUpdate()650 public void testLocalUpdate() throws Exception { 651 Cursor localCursor1 = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS + 1); 652 Cursor localCursor2 = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS + 2); 653 654 try (PickerDbFacade.DbWriteOperation operation = 655 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 656 assertWriteOperation(operation, localCursor1, 1); 657 assertWriteOperation(operation, localCursor2, 1); 658 operation.setSuccess(); 659 } 660 661 try (Cursor cr = queryMediaAll(mFacade)) { 662 assertWithMessage( 663 "Unexpected number of media after addMediaOperation with two localCursor where " 664 + "\nlocalCursor1 has localId = " + LOCAL_ID 665 + "\nlocalCursor2 has localId = " + LOCAL_ID) 666 .that(cr.getCount()).isEqualTo(1); 667 cr.moveToFirst(); 668 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS + 2); 669 } 670 671 assertRemoveMediaOperation(mFacade, LOCAL_PROVIDER, getDeletedMediaCursor(LOCAL_ID), 1); 672 673 try (Cursor cr = queryMediaAll(mFacade)) { 674 assertWithMessage( 675 "Unexpected number of media after removeMediaOperation on local provider.") 676 .that(cr.getCount()).isEqualTo(0); 677 } 678 } 679 680 @Test testCloudUpdate_withoutLocal()681 public void testCloudUpdate_withoutLocal() throws Exception { 682 Cursor cloudCursor1 = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS + 1); 683 Cursor cloudCursor2 = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS + 2); 684 685 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor1, 1); 686 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor2, 1); 687 688 try (Cursor cr = queryMediaAll(mFacade)) { 689 assertWithMessage( 690 "Unexpected number of media after addMediaOperation with two cloudCursor where " 691 + "\ncloudCursor1 has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID 692 + "\ncloudCursor2 has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID 693 ) 694 .that(cr.getCount()).isEqualTo(1); 695 cr.moveToFirst(); 696 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS + 2); 697 } 698 699 assertRemoveMediaOperation(mFacade, CLOUD_PROVIDER, getDeletedMediaCursor(CLOUD_ID), 1); 700 701 try (Cursor cr = queryMediaAll(mFacade)) { 702 assertWithMessage( 703 "Unexpected number of media after removeMediaOperation on cloud provider.") 704 .that(cr.getCount()).isEqualTo(0); 705 } 706 } 707 708 @Test testCloudUpdate_withLocal()709 public void testCloudUpdate_withLocal() throws Exception { 710 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 711 Cursor cloudCursor1 = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS + 1); 712 Cursor cloudCursor2 = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS + 2); 713 714 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 715 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor1, 1); 716 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor2, 1); 717 718 try (Cursor cr = queryMediaAll(mFacade)) { 719 assertWithMessage( 720 "Unexpected number of media after addMediaOperation with one localCursor and " 721 + "two cloudCursor, where \nlocalCursor has localId = " 722 + LOCAL_ID + "\ncloudCursor1 has localId = " + LOCAL_ID + ", cloudId = " 723 + CLOUD_ID + "\ncloudCursor1 has localId = " + LOCAL_ID + ", cloudId = " 724 + CLOUD_ID) 725 .that(cr.getCount()).isEqualTo(1); 726 cr.moveToFirst(); 727 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 728 } 729 730 assertRemoveMediaOperation(mFacade, LOCAL_PROVIDER, getDeletedMediaCursor(LOCAL_ID), 1); 731 732 try (Cursor cr = queryMediaAll(mFacade)) { 733 assertWithMessage( 734 "Unexpected number of media after removeMediaOperation deleting media with " 735 + "localId =" 736 + LOCAL_ID + " from local provider.") 737 .that(cr.getCount()).isEqualTo(1); 738 cr.moveToFirst(); 739 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS + 2); 740 } 741 742 assertRemoveMediaOperation(mFacade, CLOUD_PROVIDER, getDeletedMediaCursor(CLOUD_ID), 1); 743 744 try (Cursor cr = queryMediaAll(mFacade)) { 745 assertWithMessage( 746 "Unexpected number of media after removeMediaOperation deleting media with " 747 + "cloudId =" 748 + CLOUD_ID + " from cloud provider.") 749 .that(cr.getCount()).isEqualTo(0); 750 } 751 } 752 753 @Test testRemoveMedia_withLatestDateTakenMillis()754 public void testRemoveMedia_withLatestDateTakenMillis() { 755 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 756 Cursor cloudCursor1 = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS + 1); 757 758 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 759 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor1, 1); 760 761 try (Cursor cr = queryMediaAll(mFacade)) { 762 assertWithMessage( 763 "Unexpected number of media after addMediaOperation with one localCursor and " 764 + "one cloudCursor where " 765 + "\nlocalCursor has localId = " + LOCAL_ID 766 + "\ncloudCursor1 has localId = " + LOCAL_ID + ", cloudId = " 767 + CLOUD_ID) 768 .that(cr.getCount()).isEqualTo(1); 769 cr.moveToFirst(); 770 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 771 } 772 773 try (PickerDbFacade.DbWriteOperation operation = 774 mFacade.beginRemoveMediaOperation(CLOUD_PROVIDER)) { 775 assertWriteOperation(operation, getDeletedMediaCursor(CLOUD_ID), /* writeCount */ 1); 776 assertWithMessage( 777 "Unexpected value for the firstDateTakenMillis in the columns affected by DB " 778 + "write operation.") 779 .that(operation.getFirstDateTakenMillis()).isEqualTo(DATE_TAKEN_MS + 1); 780 operation.setSuccess(); 781 } 782 783 try (PickerDbFacade.DbWriteOperation operation = 784 mFacade.beginRemoveMediaOperation(LOCAL_PROVIDER)) { 785 assertWriteOperation(operation, getDeletedMediaCursor(LOCAL_ID), /* writeCount */ 1); 786 assertWithMessage( 787 "Unexpected value for the FirstDateTakenMillis in the columns affected by DB " 788 + "write operation.") 789 .that(operation.getFirstDateTakenMillis()).isEqualTo(DATE_TAKEN_MS); 790 operation.setSuccess(); 791 } 792 793 try (Cursor cr = queryMediaAll(mFacade)) { 794 assertWithMessage( 795 "Unexpected number of media after removeMediaOperation on cloud provider then" 796 + " on local provider.") 797 .that(cr.getCount()).isEqualTo(0); 798 } 799 } 800 801 @Test testResetLocal()802 public void testResetLocal() throws Exception { 803 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 804 // Add two cloud_ids mapping to the same local_id to verify that 805 // only one gets promoted 806 Cursor cloudCursor1 = getCloudMediaCursor(CLOUD_ID + "1", LOCAL_ID, DATE_TAKEN_MS); 807 Cursor cloudCursor2 = getCloudMediaCursor(CLOUD_ID + "2", LOCAL_ID, DATE_TAKEN_MS); 808 809 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 810 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor1, 1); 811 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor2, 1); 812 813 try (Cursor cr = queryMediaAll(mFacade)) { 814 assertWithMessage( 815 "Unexpected number of media after addMediaOperation with one localCursor and " 816 + "two cloudCursor, where \nlocalCursor has localId = " + LOCAL_ID 817 + "\ncloudCursor1 has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID 818 + "1" 819 + "\ncloudCursor1 has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID 820 + "2") 821 .that(cr.getCount()).isEqualTo(1); 822 cr.moveToFirst(); 823 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 824 } 825 826 assertResetMediaOperation(mFacade, LOCAL_PROVIDER, null, 1); 827 828 try (Cursor cr = queryMediaAll(mFacade)) { 829 assertWithMessage( 830 "Unexpected number of media after resetMediaOperation on local provider.") 831 .that(cr.getCount()).isEqualTo(1); 832 cr.moveToFirst(); 833 834 // Verify that local_id was deleted and either of cloudCursor1 or cloudCursor2 835 // was promoted 836 assertWithMessage("Failed to delete local_Id.") 837 .that(cr.getString(1)).isNotNull(); 838 } 839 } 840 841 @Test testResetCloud()842 public void testResetCloud() throws Exception { 843 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 844 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS); 845 846 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 847 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 848 849 try (Cursor cr = queryMediaAll(mFacade)) { 850 assertWithMessage( 851 "Unexpected number of media after addMediaOperation with one localCursor and " 852 + "one cloudCursor where " 853 + "\nlocalCursor has localId = " + LOCAL_ID 854 + "\ncloudCursor has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID) 855 .that(cr.getCount()).isEqualTo(1); 856 cr.moveToFirst(); 857 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 858 } 859 860 assertResetMediaOperation(mFacade, CLOUD_PROVIDER, null, 1); 861 862 try (Cursor cr = queryMediaAll(mFacade)) { 863 assertWithMessage( 864 "Unexpected number of media after resetMediaOperation on cloud provider.") 865 .that(cr.getCount()).isEqualTo(1); 866 cr.moveToFirst(); 867 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 868 } 869 } 870 871 @Test testQueryWithDateTakenFilter()872 public void testQueryWithDateTakenFilter() throws Exception { 873 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 874 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, LOCAL_ID, DATE_TAKEN_MS); 875 876 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 877 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 878 879 try (Cursor cr = queryMediaAll(mFacade)) { 880 assertWithMessage( 881 "Unexpected number of media after addMediaOperation with one localCursor and " 882 + "one cloudCursor where " 883 + "\nlocalCursor has localId = " + LOCAL_ID 884 + "\ncloudCursor has localId = " + LOCAL_ID + ", cloudId = " + CLOUD_ID) 885 .that(cr.getCount()).isEqualTo(1); 886 } 887 888 PickerDbFacade.QueryFilterBuilder qfbBefore = new PickerDbFacade.QueryFilterBuilder(5); 889 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS - 1); 890 qfbBefore.setId(5); 891 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 892 assertWithMessage( 893 "Unexpected number of media with dateTakenBeforeMs set to DATE_TAKEN_MS - 1.") 894 .that(cr.getCount()).isEqualTo(0); 895 } 896 897 PickerDbFacade.QueryFilterBuilder qfbAfter = new PickerDbFacade.QueryFilterBuilder(5); 898 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS + 1); 899 qfbAfter.setId(5); 900 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 901 assertWithMessage( 902 "Unexpected number of media with dateTakenAfterMs set to DATE_TAKEN_MS + 1.") 903 .that(cr.getCount()).isEqualTo(0); 904 } 905 } 906 907 @Test testQueryWithIdFilter()908 public void testQueryWithIdFilter() throws Exception { 909 Cursor cursor1 = getLocalMediaCursor(LOCAL_ID + "1", DATE_TAKEN_MS); 910 Cursor cursor2 = getLocalMediaCursor(LOCAL_ID + "2", DATE_TAKEN_MS); 911 912 try (PickerDbFacade.DbWriteOperation operation = 913 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 914 assertWriteOperation(operation, cursor1, 1); 915 assertWriteOperation(operation, cursor2, 1); 916 operation.setSuccess(); 917 } 918 919 PickerDbFacade.QueryFilterBuilder qfbBefore = new PickerDbFacade.QueryFilterBuilder(5); 920 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS); 921 qfbBefore.setId(2); 922 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 923 assertWithMessage("Unexpected number of media with Id set to 2.") 924 .that(cr.getCount()).isEqualTo(1); 925 926 cr.moveToFirst(); 927 assertCloudMediaCursor(cr, LOCAL_ID + "1", DATE_TAKEN_MS); 928 } 929 930 PickerDbFacade.QueryFilterBuilder qfbAfter = new PickerDbFacade.QueryFilterBuilder(5); 931 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS); 932 qfbAfter.setId(1); 933 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 934 assertWithMessage("Unexpected number of media with Id set to 1.") 935 .that(cr.getCount()).isEqualTo(1); 936 937 cr.moveToFirst(); 938 assertCloudMediaCursor(cr, LOCAL_ID + "2", DATE_TAKEN_MS); 939 } 940 } 941 942 @Test testQueryWithLimit()943 public void testQueryWithLimit() throws Exception { 944 Cursor cursor1 = getLocalMediaCursor(LOCAL_ID + "1", DATE_TAKEN_MS); 945 Cursor cursor2 = getCloudMediaCursor(CLOUD_ID + "2", null, DATE_TAKEN_MS); 946 Cursor cursor3 = getLocalMediaCursor(LOCAL_ID + "3", DATE_TAKEN_MS); 947 948 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor1, 1); 949 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor2, 1); 950 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor3, 1); 951 952 PickerDbFacade.QueryFilterBuilder qfbBefore = new PickerDbFacade.QueryFilterBuilder(1); 953 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS + 1); 954 qfbBefore.setId(0); 955 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 956 assertWithMessage( 957 "Unexpected number of media with limit set to 1 and dateTakenBeforeMs set to " 958 + "DATE_TAKEN_MS + 1.") 959 .that(cr.getCount()).isEqualTo(1); 960 961 cr.moveToFirst(); 962 assertCloudMediaCursor(cr, LOCAL_ID + "3", DATE_TAKEN_MS); 963 } 964 965 PickerDbFacade.QueryFilterBuilder qfbAfter = new PickerDbFacade.QueryFilterBuilder(1); 966 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS - 1); 967 qfbAfter.setId(0); 968 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 969 assertWithMessage( 970 "Unexpected number of media with limit set to 1 and dateTakenAfterMs set to " 971 + "DATE_TAKEN_MS - 1.") 972 .that(cr.getCount()).isEqualTo(1); 973 974 cr.moveToFirst(); 975 assertCloudMediaCursor(cr, LOCAL_ID + "3", DATE_TAKEN_MS); 976 } 977 978 try (Cursor cr = mFacade.queryMediaForUi( 979 new PickerDbFacade.QueryFilterBuilder(1).build())) { 980 assertWithMessage("Unexpected number of media with limit set to 1.") 981 .that(cr.getCount()).isEqualTo(1); 982 983 cr.moveToFirst(); 984 assertCloudMediaCursor(cr, LOCAL_ID + "3", DATE_TAKEN_MS); 985 } 986 } 987 988 @Test testQueryWithSizeFilter()989 public void testQueryWithSizeFilter() throws Exception { 990 Cursor cursor1 = getMediaCursor(LOCAL_ID, DATE_TAKEN_MS, GENERATION_MODIFIED, 991 /* mediaStoreUri */ null, /* sizeBytes */ 1, MP4_VIDEO_MIME_TYPE, 992 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 993 Cursor cursor2 = getMediaCursor(CLOUD_ID, DATE_TAKEN_MS, GENERATION_MODIFIED, 994 /* mediaStoreUri */ null, /* sizeBytes */ 2, MP4_VIDEO_MIME_TYPE, 995 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 996 997 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor1, 1); 998 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor2, 1); 999 1000 // Verify all 1001 PickerDbFacade.QueryFilterBuilder qfbAll = new PickerDbFacade.QueryFilterBuilder(1000); 1002 qfbAll.setSizeBytes(10); 1003 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1004 assertWithMessage("Unexpected number of media with sizeBytes set to 10.") 1005 .that(cr.getCount()).isEqualTo(2); 1006 } 1007 1008 qfbAll.setSizeBytes(1); 1009 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1010 assertWithMessage("Unexpected number of media with sizeBytes set to 1.") 1011 .that(cr.getCount()).isEqualTo(1); 1012 1013 cr.moveToFirst(); 1014 assertCloudMediaCursor(cr, LOCAL_ID, MP4_VIDEO_MIME_TYPE); 1015 } 1016 1017 // Verify after 1018 PickerDbFacade.QueryFilterBuilder qfbAfter = new PickerDbFacade.QueryFilterBuilder(1000); 1019 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS - 1); 1020 qfbAfter.setId(0); 1021 qfbAfter.setSizeBytes(10); 1022 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 1023 assertWithMessage( 1024 "Unexpected number of media with sizeBytes set to 10 and dateTakenAfterMs set" 1025 + " to DATE_TAKEN_MS - 1.") 1026 .that(cr.getCount()).isEqualTo(2); 1027 } 1028 1029 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS - 1); 1030 qfbAfter.setId(0); 1031 qfbAfter.setSizeBytes(1); 1032 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 1033 assertWithMessage( 1034 "Unexpected number of media with sizeBytes set to 1 and dateTakenAfterMs set " 1035 + "to DATE_TAKEN_MS - 1.") 1036 .that(cr.getCount()).isEqualTo(1); 1037 1038 cr.moveToFirst(); 1039 assertCloudMediaCursor(cr, LOCAL_ID, MP4_VIDEO_MIME_TYPE); 1040 } 1041 1042 // Verify before 1043 PickerDbFacade.QueryFilterBuilder qfbBefore = new PickerDbFacade.QueryFilterBuilder(1000); 1044 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS + 1); 1045 qfbBefore.setId(0); 1046 qfbBefore.setSizeBytes(10); 1047 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 1048 assertWithMessage( 1049 "Unexpected number of media with sizeBytes set to 10 and dateTakenBeforeMs " 1050 + "set to DATE_TAKEN_MS + 1.") 1051 .that(cr.getCount()).isEqualTo(2); 1052 } 1053 1054 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS + 1); 1055 qfbBefore.setId(0); 1056 qfbBefore.setSizeBytes(1); 1057 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 1058 assertWithMessage( 1059 "Unexpected number of media with sizeBytes set to 1 and dateTakenBeforeMs set" 1060 + " to DATE_TAKEN_MS + 1.") 1061 .that(cr.getCount()).isEqualTo(1); 1062 1063 cr.moveToFirst(); 1064 assertCloudMediaCursor(cr, LOCAL_ID, MP4_VIDEO_MIME_TYPE); 1065 } 1066 } 1067 1068 @Test testQueryWithMimeTypesFilter()1069 public void testQueryWithMimeTypesFilter() throws Exception { 1070 Cursor cursor1 = getMediaCursor(LOCAL_ID_1, DATE_TAKEN_MS, GENERATION_MODIFIED, 1071 /* mediaStoreUri */ null, SIZE_BYTES, WEBM_VIDEO_MIME_TYPE, 1072 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1073 Cursor cursor2 = getMediaCursor(LOCAL_ID_2, DATE_TAKEN_MS, GENERATION_MODIFIED, 1074 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1075 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1076 Cursor cursor3 = getMediaCursor(CLOUD_ID_1, DATE_TAKEN_MS, GENERATION_MODIFIED, 1077 /* mediaStoreUri */ null, SIZE_BYTES, PNG_IMAGE_MIME_TYPE, 1078 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1079 Cursor cursor4 = getMediaCursor(CLOUD_ID_2, DATE_TAKEN_MS, GENERATION_MODIFIED, 1080 /* mediaStoreUri */ null, SIZE_BYTES, GIF_IMAGE_MIME_TYPE, 1081 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1082 Cursor cursor5 = getMediaCursor(CLOUD_ID_3, DATE_TAKEN_MS - 1, GENERATION_MODIFIED, 1083 /* mediaStoreUri */ null, SIZE_BYTES, PNG_IMAGE_MIME_TYPE, 1084 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1085 Cursor cursor6 = getMediaCursor(LOCAL_ID_3, DATE_TAKEN_MS + 1, GENERATION_MODIFIED, 1086 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1087 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1088 1089 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor1, 1); 1090 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor2, 1); 1091 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor3, 1); 1092 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor4, 1); 1093 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor5, 1); 1094 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor6, 1); 1095 1096 // Verify all 1097 PickerDbFacade.QueryFilterBuilder qfbAll = new PickerDbFacade.QueryFilterBuilder(1000); 1098 qfbAll.setMimeTypes(new String[]{"*/*"}); 1099 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1100 assertWithMessage( 1101 "Unexpected number of rows with mime_type filter set to {\"*/*\"}") 1102 .that(cr.getCount()).isEqualTo(6); 1103 } 1104 1105 qfbAll.setMimeTypes(new String[]{"image/*"}); 1106 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1107 assertWithMessage( 1108 "Unexpected number of rows with mime_type filter set to {\"image/*\"}") 1109 .that(cr.getCount()).isEqualTo(4); 1110 1111 assertAllMediaCursor(cr, 1112 new String[]{CLOUD_ID_2, CLOUD_ID_1, LOCAL_ID_2, CLOUD_ID_3}, 1113 new long[]{DATE_TAKEN_MS, DATE_TAKEN_MS, DATE_TAKEN_MS, DATE_TAKEN_MS - 1}, 1114 new String[]{GIF_IMAGE_MIME_TYPE, PNG_IMAGE_MIME_TYPE, 1115 JPEG_IMAGE_MIME_TYPE, PNG_IMAGE_MIME_TYPE}); 1116 } 1117 1118 qfbAll.setMimeTypes(new String[]{"video/*"}); 1119 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1120 assertWithMessage( 1121 "Unexpected number of rows with mime_type filter set to {\"video/*\"}") 1122 .that(cr.getCount()).isEqualTo(2); 1123 1124 assertAllMediaCursor(cr, 1125 new String[]{LOCAL_ID_3, LOCAL_ID_1}, 1126 new long[]{DATE_TAKEN_MS + 1, DATE_TAKEN_MS}, 1127 new String[]{MP4_VIDEO_MIME_TYPE, WEBM_VIDEO_MIME_TYPE}); 1128 } 1129 1130 // Verify after 1131 PickerDbFacade.QueryFilterBuilder qfbAfter = new PickerDbFacade.QueryFilterBuilder(1000); 1132 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS); 1133 qfbAfter.setId(0); 1134 qfbAfter.setMimeTypes(new String[]{"image/*"}); 1135 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 1136 assertWithMessage( 1137 "Unexpected number of rows with mime_type filter set to {\"image/*\"} " 1138 + "and date taken after set to DATE_TAKEN_MS") 1139 .that(cr.getCount()).isEqualTo(3); 1140 } 1141 1142 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS - 1); 1143 qfbAfter.setId(0); 1144 qfbAfter.setMimeTypes(new String[]{PNG_IMAGE_MIME_TYPE}); 1145 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 1146 assertWithMessage( 1147 "Unexpected number of rows with mime_type filter set to " 1148 + "{PNG_IMAGE_MIME_TYPE} and date taken after set to DATE_TAKEN_MS - 1") 1149 .that(cr.getCount()).isEqualTo(2); 1150 1151 assertAllMediaCursor(cr, 1152 new String[]{CLOUD_ID_1, CLOUD_ID_3}, 1153 new long[]{DATE_TAKEN_MS, DATE_TAKEN_MS - 1}, 1154 new String[]{PNG_IMAGE_MIME_TYPE, PNG_IMAGE_MIME_TYPE}); 1155 } 1156 1157 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS - 1); 1158 qfbAfter.setId(0); 1159 qfbAfter.setMimeTypes(new String[]{"video/*"}); 1160 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 1161 assertWithMessage( 1162 "Unexpected number of rows with mime_type filter set to {\"video/*\"} " 1163 + "and date taken after set to DATE_TAKEN_MS - 1") 1164 .that(cr.getCount()).isEqualTo(2); 1165 1166 assertAllMediaCursor(cr, 1167 new String[]{LOCAL_ID_3, LOCAL_ID_1}, 1168 new long[]{DATE_TAKEN_MS + 1, DATE_TAKEN_MS}, 1169 new String[]{MP4_VIDEO_MIME_TYPE, WEBM_VIDEO_MIME_TYPE}); 1170 } 1171 1172 // Verify before 1173 PickerDbFacade.QueryFilterBuilder qfbBefore = new PickerDbFacade.QueryFilterBuilder(1000); 1174 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS + 1); 1175 qfbBefore.setId(0); 1176 qfbBefore.setMimeTypes(new String[]{"*/*"}); 1177 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 1178 assertWithMessage( 1179 "Unexpected number of rows with mime_type filter set to {\"*/*\"} and " 1180 + "date taken before set to DATE_TAKEN_MS + 1") 1181 .that(cr.getCount()).isEqualTo(5); 1182 } 1183 1184 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS + 1); 1185 qfbBefore.setId(0); 1186 qfbBefore.setMimeTypes(new String[]{"video/*"}); 1187 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 1188 assertWithMessage( 1189 "Unexpected number of rows with mime_type filter set to {\"video/*\"} " 1190 + "and date taken before set to DATE_TAKEN_MS + 1") 1191 .that(cr.getCount()).isEqualTo(1); 1192 1193 cr.moveToFirst(); 1194 assertCloudMediaCursor(cr, LOCAL_ID_1, DATE_TAKEN_MS, WEBM_VIDEO_MIME_TYPE); 1195 } 1196 1197 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS + 2); 1198 qfbBefore.setId(0); 1199 qfbBefore.setMimeTypes(new String[]{"video/*"}); 1200 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 1201 assertWithMessage( 1202 "Unexpected number of rows with mime_type filter set to {\"video/*\"} " 1203 + "and date taken before set to DATE_TAKEN_MS + 2") 1204 .that(cr.getCount()).isEqualTo(2); 1205 1206 assertAllMediaCursor(cr, 1207 new String[]{LOCAL_ID_3, LOCAL_ID_1}, 1208 new long[]{DATE_TAKEN_MS + 1, DATE_TAKEN_MS}, 1209 new String[]{MP4_VIDEO_MIME_TYPE, WEBM_VIDEO_MIME_TYPE}); 1210 } 1211 1212 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS + 1); 1213 qfbBefore.setId(0); 1214 qfbBefore.setMimeTypes(new String[]{PNG_IMAGE_MIME_TYPE}); 1215 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 1216 assertWithMessage( 1217 "Unexpected number of rows with mime_type filter set to " 1218 + "{PNG_IMAGE_MIME_TYPE} and date taken before set to DATE_TAKEN_MS +" 1219 + " 1") 1220 .that(cr.getCount()).isEqualTo(2); 1221 1222 assertAllMediaCursor(cr, 1223 new String[]{CLOUD_ID_1, CLOUD_ID_3}, 1224 new long[]{DATE_TAKEN_MS, DATE_TAKEN_MS - 1}, 1225 new String[]{PNG_IMAGE_MIME_TYPE, PNG_IMAGE_MIME_TYPE}); 1226 } 1227 } 1228 1229 @Test testQueryWithMultipleMimeTypesFilter()1230 public void testQueryWithMultipleMimeTypesFilter() throws Exception { 1231 Cursor cursor1 = getMediaCursor(LOCAL_ID_1, DATE_TAKEN_MS, GENERATION_MODIFIED, 1232 /* mediaStoreUri */ null, SIZE_BYTES, WEBM_VIDEO_MIME_TYPE, 1233 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1234 Cursor cursor2 = getMediaCursor(LOCAL_ID_2, DATE_TAKEN_MS, GENERATION_MODIFIED, 1235 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1236 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1237 Cursor cursor3 = getMediaCursor(LOCAL_ID_3, DATE_TAKEN_MS, GENERATION_MODIFIED, 1238 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1239 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1240 Cursor cursor4 = getMediaCursor(CLOUD_ID_1, DATE_TAKEN_MS, GENERATION_MODIFIED, 1241 /* mediaStoreUri */ null, SIZE_BYTES, PNG_IMAGE_MIME_TYPE, 1242 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1243 Cursor cursor5 = getMediaCursor(CLOUD_ID_2, DATE_TAKEN_MS, GENERATION_MODIFIED, 1244 /* mediaStoreUri */ null, SIZE_BYTES, GIF_IMAGE_MIME_TYPE, 1245 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1246 Cursor cursor6 = getMediaCursor(CLOUD_ID_3, DATE_TAKEN_MS, GENERATION_MODIFIED, 1247 /* mediaStoreUri */ null, SIZE_BYTES, MPEG_VIDEO_MIME_TYPE, 1248 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1249 Cursor cursor7 = getMediaCursor(CLOUD_ID_4, DATE_TAKEN_MS - 1, GENERATION_MODIFIED, 1250 /* mediaStoreUri */ null, SIZE_BYTES, PNG_IMAGE_MIME_TYPE, 1251 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1252 Cursor cursor8 = getMediaCursor(LOCAL_ID_4, DATE_TAKEN_MS + 1, GENERATION_MODIFIED, 1253 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1254 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1255 1256 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor1, 1); 1257 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor2, 1); 1258 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor3, 1); 1259 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor4, 1); 1260 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor5, 1); 1261 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor6, 1); 1262 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor7, 1); 1263 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor8, 1); 1264 1265 // Verify all 1266 PickerDbFacade.QueryFilterBuilder qfbAll = new PickerDbFacade.QueryFilterBuilder(1000); 1267 qfbAll.setMimeTypes(new String[]{"*/*"}); 1268 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1269 assertWithMessage( 1270 "Unexpected number of rows with mime_type filter set to {\"*/*\"}") 1271 .that(cr.getCount()).isEqualTo(8); 1272 } 1273 1274 qfbAll.setMimeTypes(new String[]{"image/*", PNG_IMAGE_MIME_TYPE, MP4_VIDEO_MIME_TYPE}); 1275 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1276 assertWithMessage( 1277 "Unexpected number of rows with mime_type filter set to {\"image/*\"," 1278 + "PNG_IMAGE_MIME_TYPE ,PNG_IMAGE_MIME_TYPE}") 1279 .that(cr.getCount()).isEqualTo(6); 1280 } 1281 1282 qfbAll.setMimeTypes(new String[]{GIF_IMAGE_MIME_TYPE, MPEG_VIDEO_MIME_TYPE, 1283 WEBM_VIDEO_MIME_TYPE}); 1284 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1285 assertWithMessage( 1286 "Unexpected number of rows with mime_type filter set to " 1287 + "{GIF_IMAGE_MIME_TYPE, MPEG_VIDEO_MIME_TYPE, WEBM_VIDEO_MIME_TYPE}") 1288 .that(cr.getCount()).isEqualTo(3); 1289 1290 assertAllMediaCursor(cr, new String[]{CLOUD_ID_3, CLOUD_ID_2, LOCAL_ID_1}, 1291 new long[]{DATE_TAKEN_MS, DATE_TAKEN_MS, DATE_TAKEN_MS}, new String[]{ 1292 MPEG_VIDEO_MIME_TYPE, GIF_IMAGE_MIME_TYPE, WEBM_VIDEO_MIME_TYPE}); 1293 } 1294 1295 // Verify after 1296 PickerDbFacade.QueryFilterBuilder qfbAfter = new PickerDbFacade.QueryFilterBuilder(1000); 1297 1298 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS - 1); 1299 qfbAfter.setId(0); 1300 qfbAfter.setMimeTypes(new String[]{"video/*"}); 1301 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 1302 assertWithMessage( 1303 "Unexpected number of rows with mime_type filter set to {\"video/*\"} " 1304 + "and date taken after set to DATE_TAKEN_MS - 1") 1305 .that(cr.getCount()).isEqualTo(4); 1306 } 1307 1308 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS - 1); 1309 qfbAfter.setId(0); 1310 qfbAfter.setMimeTypes(new String[]{GIF_IMAGE_MIME_TYPE, 1311 MPEG_VIDEO_MIME_TYPE, WEBM_VIDEO_MIME_TYPE, M4V_VIDEO_MIME_TYPE}); 1312 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 1313 assertWithMessage( 1314 "Unexpected number of rows with mime_type filter set to " 1315 + "{GIF_IMAGE_MIME_TYPE, MPEG_VIDEO_MIME_TYPE, WEBM_VIDEO_MIME_TYPE, " 1316 + "M4V_VIDEO_MIME_TYPE} and date taken after set to DATE_TAKEN_MS - 1") 1317 .that(cr.getCount()).isEqualTo(3); 1318 1319 assertAllMediaCursor(cr, new String[]{CLOUD_ID_3, CLOUD_ID_2, LOCAL_ID_1}, 1320 new long[]{DATE_TAKEN_MS, DATE_TAKEN_MS, DATE_TAKEN_MS}, new String[]{ 1321 MPEG_VIDEO_MIME_TYPE, GIF_IMAGE_MIME_TYPE, WEBM_VIDEO_MIME_TYPE}); 1322 } 1323 1324 qfbAfter.setDateTakenAfterMs(DATE_TAKEN_MS - 1); 1325 qfbAfter.setId(0); 1326 qfbAfter.setMimeTypes(new String[]{GIF_IMAGE_MIME_TYPE, MP4_VIDEO_MIME_TYPE}); 1327 try (Cursor cr = mFacade.queryMediaForUi(qfbAfter.build())) { 1328 assertWithMessage( 1329 "Unexpected number of rows with mime_type filter set to " 1330 + "{GIF_IMAGE_MIME_TYPE, MP4_VIDEO_MIME_TYPE} and date taken after " 1331 + "set to DATE_TAKEN_MS - 1") 1332 .that(cr.getCount()).isEqualTo(3); 1333 } 1334 1335 // Verify before 1336 PickerDbFacade.QueryFilterBuilder qfbBefore = new PickerDbFacade.QueryFilterBuilder(1000); 1337 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS + 1); 1338 qfbBefore.setId(0); 1339 qfbBefore.setMimeTypes(new String[]{"*/*"}); 1340 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 1341 assertWithMessage( 1342 "Unexpected number of rows with mime_type filter set to {\"*/*\"} and " 1343 + "date taken before set to DATE_TAKEN_MS + 1") 1344 .that(cr.getCount()).isEqualTo(7); 1345 } 1346 1347 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS); 1348 qfbBefore.setId(0); 1349 qfbBefore.setMimeTypes(new String[]{"image/*"}); 1350 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 1351 assertWithMessage( 1352 "Unexpected number of rows with mime_type filter set to {\"image/*\"} " 1353 + "and date taken before set to DATE_TAKEN_MS") 1354 .that(cr.getCount()).isEqualTo(1); 1355 1356 cr.moveToFirst(); 1357 assertCloudMediaCursor(cr, CLOUD_ID_4, DATE_TAKEN_MS - 1, PNG_IMAGE_MIME_TYPE); 1358 } 1359 1360 qfbBefore.setDateTakenBeforeMs(DATE_TAKEN_MS + 2); 1361 qfbBefore.setId(0); 1362 qfbBefore.setMimeTypes(new String[]{MP4_VIDEO_MIME_TYPE, GIF_IMAGE_MIME_TYPE}); 1363 try (Cursor cr = mFacade.queryMediaForUi(qfbBefore.build())) { 1364 assertWithMessage( 1365 "Unexpected number of rows with mime_type filter set to " 1366 + "{MP4_VIDEO_MIME_TYPE, GIF_IMAGE_MIME_TYPE} and date taken before " 1367 + "set to DATE_TAKEN_MS + 2") 1368 .that(cr.getCount()).isEqualTo(3); 1369 1370 assertAllMediaCursor(cr, new String[]{LOCAL_ID_4, CLOUD_ID_2, LOCAL_ID_3}, 1371 new long[]{DATE_TAKEN_MS + 1, DATE_TAKEN_MS, DATE_TAKEN_MS}, new String[]{ 1372 MP4_VIDEO_MIME_TYPE, GIF_IMAGE_MIME_TYPE, MP4_VIDEO_MIME_TYPE}); 1373 } 1374 } 1375 1376 @Test testQueryWithSizeAndMimeTypesFilter()1377 public void testQueryWithSizeAndMimeTypesFilter() throws Exception { 1378 Cursor cursor1 = getMediaCursor(LOCAL_ID, DATE_TAKEN_MS, GENERATION_MODIFIED, 1379 /* mediaStoreUri */ null, /* sizeBytes */ 2, WEBM_VIDEO_MIME_TYPE, 1380 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1381 Cursor cursor2 = getMediaCursor(CLOUD_ID, DATE_TAKEN_MS, GENERATION_MODIFIED, 1382 /* mediaStoreUri */ null, /* sizeBytes */ 1, MP4_VIDEO_MIME_TYPE, 1383 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1384 1385 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, cursor1, 1); 1386 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cursor2, 1); 1387 1388 // mime_type and size filter matches all 1389 PickerDbFacade.QueryFilterBuilder qfbAll = new PickerDbFacade.QueryFilterBuilder(1000); 1390 qfbAll.setMimeTypes(new String[]{"*/*"}); 1391 qfbAll.setSizeBytes(10); 1392 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1393 assertWithMessage( 1394 "Unexpected number of rows with mime_type filter set to {\"*/*\"} and size " 1395 + "filter set to 10 bytes") 1396 .that(cr.getCount()).isEqualTo(2); 1397 } 1398 1399 // mime_type and size filter matches none 1400 qfbAll.setMimeTypes(new String[]{WEBM_VIDEO_MIME_TYPE}); 1401 qfbAll.setSizeBytes(1); 1402 try (Cursor cr = mFacade.queryMediaForUi(qfbAll.build())) { 1403 assertWithMessage( 1404 "Unexpected number of rows with mime_type filter set to " 1405 + "{WEBM_VIDEO_MIME_TYPE} and size filter set to 1 byte") 1406 .that(cr.getCount()).isEqualTo(0); 1407 } 1408 } 1409 1410 @Test testQueryMediaId()1411 public void testQueryMediaId() throws Exception { 1412 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 1413 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, /* localId */ null, DATE_TAKEN_MS); 1414 1415 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 1416 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 1417 1418 // Assert all projection columns 1419 final String[] allProjection = mProjectionHelper.getProjectionMap( 1420 PickerMediaColumns.class).keySet().toArray(new String[0]); 1421 try (Cursor cr = mFacade.queryMediaIdForApps(PickerUriResolver.PICKER_SEGMENT, 1422 LOCAL_PROVIDER, LOCAL_ID, allProjection)) { 1423 assertWithMessage( 1424 "Unexpected number of rows when asserting all projection columns with " 1425 + "PickerUriResolver as PICKER_SEGMENT on local provider.") 1426 .that(cr.getCount()).isEqualTo(1); 1427 1428 cr.moveToFirst(); 1429 assertMediaStoreCursor(cr, LOCAL_ID, DATE_TAKEN_MS, PickerUriResolver.PICKER_SEGMENT); 1430 } 1431 1432 try (Cursor cr = mFacade.queryMediaIdForApps(PickerUriResolver.PICKER_GET_CONTENT_SEGMENT, 1433 LOCAL_PROVIDER, LOCAL_ID, allProjection)) { 1434 assertWithMessage( 1435 "Unexpected number of rows when asserting all projection columns with " 1436 + "PickerUriResolver as PICKER_GET_CONTENT_SEGMENT on local provider.") 1437 .that(cr.getCount()).isEqualTo(1); 1438 1439 cr.moveToFirst(); 1440 assertMediaStoreCursor(cr, LOCAL_ID, DATE_TAKEN_MS, 1441 PickerUriResolver.PICKER_GET_CONTENT_SEGMENT); 1442 } 1443 1444 // Assert one projection column 1445 final String[] oneProjection = new String[]{PickerMediaColumns.DATE_TAKEN}; 1446 1447 try (Cursor cr = mFacade.queryMediaIdForApps(PickerUriResolver.PICKER_SEGMENT, 1448 CLOUD_PROVIDER, CLOUD_ID, oneProjection)) { 1449 assertWithMessage( 1450 "Unexpected number of rows when asserting one projection column with cloud " 1451 + "provider.") 1452 .that(cr.getCount()).isEqualTo(1); 1453 1454 cr.moveToFirst(); 1455 assertWithMessage( 1456 "Unexpected value of PickerMediaColumns.DATE_TAKEN with cloud provider.") 1457 .that(cr.getLong(cr.getColumnIndexOrThrow(PickerMediaColumns.DATE_TAKEN))) 1458 .isEqualTo(DATE_TAKEN_MS); 1459 } 1460 1461 // Assert invalid projection column 1462 final String invalidColumn = "test invalid column"; 1463 final String[] invalidProjection = new String[]{ 1464 PickerMediaColumns.DATE_TAKEN, 1465 invalidColumn 1466 }; 1467 1468 try (Cursor cr = mFacade.queryMediaIdForApps(PickerUriResolver.PICKER_SEGMENT, 1469 CLOUD_PROVIDER, CLOUD_ID, invalidProjection)) { 1470 assertWithMessage( 1471 "Unexpected number of rows when asserting invalid projection column with " 1472 + "cloud provider.") 1473 .that(cr.getCount()).isEqualTo(1); 1474 assertWithMessage("Unexpected number of columns in cursor") 1475 .that(cr.getColumnCount()) 1476 .isEqualTo(2); 1477 1478 cr.moveToFirst(); 1479 assertWithMessage("Unexpected value of the invalidColumn with cloud provider.") 1480 .that(cr.getLong(cr.getColumnIndexOrThrow(invalidColumn))) 1481 .isEqualTo(0); 1482 assertWithMessage("Unexpected value of the invalidColumn with cloud provider.") 1483 .that(cr.getString(cr.getColumnIndexOrThrow(invalidColumn))) 1484 .isEqualTo(null); 1485 assertWithMessage( 1486 "Unexpected value of PickerMediaColumns.DATE_TAKEN with cloud provider.") 1487 .that(cr.getLong(cr.getColumnIndexOrThrow(PickerMediaColumns.DATE_TAKEN))) 1488 .isEqualTo(DATE_TAKEN_MS); 1489 } 1490 } 1491 1492 /** 1493 * Tests {@link PickerDbFacade#queryMediaForUi(PickerDbFacade.QueryFilter)} 1494 * to ensure columns not required for the UI are not present. 1495 */ 1496 @Test testQueryMediaForUi()1497 public void testQueryMediaForUi() throws Exception { 1498 1499 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 1500 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, /* localId */ null, DATE_TAKEN_MS); 1501 1502 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 1503 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 1504 1505 PickerDbFacade.QueryFilterBuilder qfb = 1506 new PickerDbFacade.QueryFilterBuilder(/* limit */ 1000); 1507 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 1508 1509 assertWithMessage( 1510 "Unexpected number of rows on queryMediaForUi.") 1511 .that(cr.getCount()).isEqualTo(2); 1512 cr.moveToFirst(); 1513 assertThrows( 1514 IllegalArgumentException.class, 1515 () -> cr.getColumnIndexOrThrow(MediaColumns.WIDTH)); 1516 assertThrows( 1517 IllegalArgumentException.class, 1518 () -> cr.getColumnIndexOrThrow(MediaColumns.HEIGHT)); 1519 assertThrows( 1520 IllegalArgumentException.class, 1521 () -> cr.getColumnIndexOrThrow(MediaColumns.ORIENTATION)); 1522 1523 cr.moveToNext(); 1524 assertThrows( 1525 IllegalArgumentException.class, 1526 () -> cr.getColumnIndexOrThrow(MediaColumns.WIDTH)); 1527 assertThrows( 1528 IllegalArgumentException.class, 1529 () -> cr.getColumnIndexOrThrow(MediaColumns.HEIGHT)); 1530 assertThrows( 1531 IllegalArgumentException.class, 1532 () -> cr.getColumnIndexOrThrow(MediaColumns.ORIENTATION)); 1533 } 1534 } 1535 1536 /** 1537 * Tests {@link PickerDbFacade#queryAlbumMediaForUi(PickerDbFacade.QueryFilter, String)} to 1538 * ensure columns not required for the UI are not present. 1539 */ 1540 @Test testQueryAlbumMediaForUi()1541 public void testQueryAlbumMediaForUi() throws Exception { 1542 1543 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 1544 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, /* localId */ null, DATE_TAKEN_MS); 1545 1546 assertAddAlbumMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1, ALBUM_ID); 1547 assertAddAlbumMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1, ALBUM_ID); 1548 1549 PickerDbFacade.QueryFilterBuilder localQfb = 1550 new PickerDbFacade.QueryFilterBuilder(/* limit */ 1000); 1551 try (Cursor cr = 1552 mFacade.queryAlbumMediaForUi( 1553 localQfb.setAlbumId(ALBUM_ID).build(), LOCAL_PROVIDER)) { 1554 assertWithMessage( 1555 "Unexpected number of rows on queryAlbumMediaForUi with local provider.") 1556 .that(cr.getCount()).isEqualTo(1); 1557 cr.moveToFirst(); 1558 assertThrows( 1559 IllegalArgumentException.class, 1560 () -> cr.getColumnIndexOrThrow(MediaColumns.WIDTH)); 1561 assertThrows( 1562 IllegalArgumentException.class, 1563 () -> cr.getColumnIndexOrThrow(MediaColumns.HEIGHT)); 1564 assertThrows( 1565 IllegalArgumentException.class, 1566 () -> cr.getColumnIndexOrThrow(MediaColumns.ORIENTATION)); 1567 } 1568 1569 PickerDbFacade.QueryFilterBuilder cloudQfb = 1570 new PickerDbFacade.QueryFilterBuilder(/* limit */ 1000); 1571 try (Cursor cr = 1572 mFacade.queryAlbumMediaForUi( 1573 cloudQfb.setAlbumId(ALBUM_ID).build(), CLOUD_PROVIDER)) { 1574 assertWithMessage( 1575 "Unexpected number of rows on queryAlbumMediaForUi with cloud provider.") 1576 .that(cr.getCount()).isEqualTo(2); 1577 cr.moveToFirst(); 1578 assertThrows( 1579 IllegalArgumentException.class, 1580 () -> cr.getColumnIndexOrThrow(MediaColumns.WIDTH)); 1581 assertThrows( 1582 IllegalArgumentException.class, 1583 () -> cr.getColumnIndexOrThrow(MediaColumns.HEIGHT)); 1584 assertThrows( 1585 IllegalArgumentException.class, 1586 () -> cr.getColumnIndexOrThrow(MediaColumns.ORIENTATION)); 1587 } 1588 } 1589 1590 @Test testSetCloudProvider()1591 public void testSetCloudProvider() throws Exception { 1592 Cursor localCursor = getLocalMediaCursor(LOCAL_ID, DATE_TAKEN_MS); 1593 Cursor cloudCursor = getCloudMediaCursor(CLOUD_ID, null, DATE_TAKEN_MS); 1594 1595 assertAddMediaOperation(mFacade, LOCAL_PROVIDER, localCursor, 1); 1596 assertAddMediaOperation(mFacade, CLOUD_PROVIDER, cloudCursor, 1); 1597 1598 try (Cursor cr = queryMediaAll(mFacade)) { 1599 assertWithMessage( 1600 "Unexpected number of rows on queryMediaAll with both local and cloud " 1601 + "provider.") 1602 .that(cr.getCount()).isEqualTo(2); 1603 1604 cr.moveToFirst(); 1605 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS); 1606 1607 cr.moveToNext(); 1608 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 1609 } 1610 1611 // Clearing the cloud provider hides cloud media 1612 mFacade.setCloudProvider(null); 1613 1614 try (Cursor cr = queryMediaAll(mFacade)) { 1615 assertWithMessage( 1616 "Unexpected number of rows on queryMediaAll after hiding cloud provider.") 1617 .that(cr.getCount()).isEqualTo(1); 1618 1619 cr.moveToFirst(); 1620 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 1621 } 1622 1623 // Setting the cloud provider unhides cloud media 1624 mFacade.setCloudProvider(CLOUD_PROVIDER); 1625 1626 try (Cursor cr = queryMediaAll(mFacade)) { 1627 assertWithMessage( 1628 "Unexpected number of rows on queryMediaAll after un-hiding cloud provider.") 1629 .that(cr.getCount()).isEqualTo(2); 1630 1631 cr.moveToFirst(); 1632 assertCloudMediaCursor(cr, CLOUD_ID, DATE_TAKEN_MS); 1633 1634 cr.moveToNext(); 1635 assertCloudMediaCursor(cr, LOCAL_ID, DATE_TAKEN_MS); 1636 } 1637 } 1638 1639 @Test testFavorites()1640 public void testFavorites() throws Exception { 1641 Cursor localCursor1 = getMediaCursor(LOCAL_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1642 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1643 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 1644 Cursor localCursor2 = getMediaCursor(LOCAL_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1645 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1646 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1647 Cursor cloudCursor1 = getMediaCursor(CLOUD_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1648 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1649 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 1650 Cursor cloudCursor2 = getMediaCursor(CLOUD_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1651 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1652 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1653 1654 try (PickerDbFacade.DbWriteOperation operation = 1655 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 1656 assertWriteOperation(operation, localCursor1, 1); 1657 assertWriteOperation(operation, localCursor2, 1); 1658 operation.setSuccess(); 1659 } 1660 try (PickerDbFacade.DbWriteOperation operation = 1661 mFacade.beginAddMediaOperation(CLOUD_PROVIDER)) { 1662 assertWriteOperation(operation, cloudCursor1, 1); 1663 assertWriteOperation(operation, cloudCursor2, 1); 1664 operation.setSuccess(); 1665 } 1666 1667 PickerDbFacade.QueryFilterBuilder qfb = 1668 new PickerDbFacade.QueryFilterBuilder(/* limit */ 1000); 1669 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 1670 assertWithMessage( 1671 "Unexpected number of rows on queryMediaForUi with no filter.") 1672 .that(cr.getCount()).isEqualTo(4); 1673 } 1674 1675 qfb.setIsFavorite(true); 1676 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 1677 assertWithMessage( 1678 "Unexpected number of rows on queryMediaForUi with isFavorite filter set to " 1679 + "true.") 1680 .that(cr.getCount()).isEqualTo(2); 1681 cr.moveToFirst(); 1682 assertCloudMediaCursor(cr, CLOUD_ID + 1, DATE_TAKEN_MS); 1683 1684 cr.moveToNext(); 1685 assertCloudMediaCursor(cr, LOCAL_ID + 1, DATE_TAKEN_MS); 1686 } 1687 } 1688 1689 @Test testGetFavoritesAlbumWithoutFilter()1690 public void testGetFavoritesAlbumWithoutFilter() throws Exception { 1691 Cursor localCursor1 = getMediaCursor(LOCAL_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1692 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1693 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 1694 Cursor localCursor2 = getMediaCursor(LOCAL_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1695 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1696 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1697 Cursor cloudCursor1 = getMediaCursor(CLOUD_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1698 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1699 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 1700 Cursor cloudCursor2 = getMediaCursor(CLOUD_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1701 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1702 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1703 1704 try (PickerDbFacade.DbWriteOperation operation = 1705 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 1706 assertWriteOperation(operation, localCursor1, 1); 1707 assertWriteOperation(operation, localCursor2, 1); 1708 operation.setSuccess(); 1709 } 1710 try (PickerDbFacade.DbWriteOperation operation = 1711 mFacade.beginAddMediaOperation(CLOUD_PROVIDER)) { 1712 assertWriteOperation(operation, cloudCursor1, 1); 1713 assertWriteOperation(operation, cloudCursor2, 1); 1714 operation.setSuccess(); 1715 } 1716 1717 PickerDbFacade.QueryFilterBuilder qfb = 1718 new PickerDbFacade.QueryFilterBuilder(/* limit */ 1000); 1719 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 1720 assertWithMessage("Unexpected number of rows on queryMediaForUi without any filter.") 1721 .that(cr.getCount()).isEqualTo(4); 1722 } 1723 1724 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), CLOUD_PROVIDER)) { 1725 assertWithMessage( 1726 "Unexpected number of rows on getMergedAlbums without any filter for cloud " 1727 + "provider.") 1728 .that(cr.getCount()).isEqualTo(2); 1729 cr.moveToFirst(); 1730 assertCloudAlbumCursor(cr, 1731 ALBUM_ID_FAVORITES, 1732 ALBUM_ID_FAVORITES, 1733 LOCAL_ID + "1", 1734 DATE_TAKEN_MS, 1735 /* count */ 2); 1736 cr.moveToNext(); 1737 assertCloudAlbumCursor(cr, 1738 ALBUM_ID_VIDEOS, 1739 ALBUM_ID_VIDEOS, 1740 LOCAL_ID + "1", 1741 DATE_TAKEN_MS, 1742 /* count */ 2); 1743 } 1744 } 1745 1746 @Test testGetVideosAlbumWithMimeTypesFilter()1747 public void testGetVideosAlbumWithMimeTypesFilter() throws Exception { 1748 Cursor localCursor1 = getMediaCursor(LOCAL_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1749 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1750 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1751 Cursor localCursor2 = getMediaCursor(LOCAL_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1752 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1753 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 1754 Cursor cloudCursor1 = getMediaCursor(CLOUD_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1755 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1756 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1757 Cursor cloudCursor2 = getMediaCursor(CLOUD_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1758 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1759 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1760 1761 try (PickerDbFacade.DbWriteOperation operation = 1762 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 1763 assertWriteOperation(operation, localCursor1, 1); 1764 assertWriteOperation(operation, localCursor2, 1); 1765 operation.setSuccess(); 1766 } 1767 try (PickerDbFacade.DbWriteOperation operation = 1768 mFacade.beginAddMediaOperation(CLOUD_PROVIDER)) { 1769 assertWriteOperation(operation, cloudCursor1, 1); 1770 assertWriteOperation(operation, cloudCursor2, 1); 1771 operation.setSuccess(); 1772 } 1773 1774 PickerDbFacade.QueryFilterBuilder qfb = 1775 new PickerDbFacade.QueryFilterBuilder(/* limit */ 1000); 1776 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 1777 assertWithMessage("Unexpected number of rows on queryMediaForUi without any filter.") 1778 .that(cr.getCount()).isEqualTo(4); 1779 } 1780 1781 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), CLOUD_PROVIDER)) { 1782 assertWithMessage( 1783 "Unexpected number of rows on getMergedAlbums without any filter for cloud " 1784 + "provider.") 1785 .that(cr.getCount()).isEqualTo(2); 1786 cr.moveToFirst(); 1787 assertCloudAlbumCursor(cr, 1788 ALBUM_ID_FAVORITES, 1789 ALBUM_ID_FAVORITES, 1790 LOCAL_ID + "2", 1791 DATE_TAKEN_MS, 1792 /* count */ 1); 1793 cr.moveToNext(); 1794 assertCloudAlbumCursor(cr, 1795 ALBUM_ID_VIDEOS, 1796 ALBUM_ID_VIDEOS, 1797 LOCAL_ID + "1", 1798 DATE_TAKEN_MS, 1799 /* count */ 2); 1800 } 1801 1802 qfb.setMimeTypes(new String[]{MP4_VIDEO_MIME_TYPE, JPEG_IMAGE_MIME_TYPE}); 1803 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), /* cloudProvider*/ CLOUD_PROVIDER)) { 1804 assertWithMessage( 1805 "Unexpected number of rows on getMergedAlbums without any filter for cloud " 1806 + "provider.") 1807 .that(cr.getCount()).isEqualTo(2); 1808 cr.moveToFirst(); 1809 assertCloudAlbumCursor(cr, 1810 ALBUM_ID_FAVORITES, 1811 ALBUM_ID_FAVORITES, 1812 LOCAL_ID + "2", 1813 DATE_TAKEN_MS, 1814 /* count */ 1); 1815 cr.moveToNext(); 1816 assertCloudAlbumCursor(cr, 1817 ALBUM_ID_VIDEOS, 1818 ALBUM_ID_VIDEOS, 1819 LOCAL_ID + "1", 1820 DATE_TAKEN_MS, 1821 /* count */ 2); 1822 } 1823 1824 qfb.setMimeTypes(new String[]{GIF_IMAGE_MIME_TYPE, JPEG_IMAGE_MIME_TYPE}); 1825 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), /* cloudProvider*/ CLOUD_PROVIDER)) { 1826 assertWithMessage( 1827 "Unexpected number of rows on getMergedAlbums with mime type filter set to " 1828 + "{GIF_IMAGE_MIME_TYPE, JPEG_IMAGE_MIME_TYPE} for cloud provider.") 1829 .that(cr.getCount()).isEqualTo(1); 1830 cr.moveToFirst(); 1831 assertCloudAlbumCursor(cr, 1832 ALBUM_ID_FAVORITES, 1833 ALBUM_ID_FAVORITES, 1834 LOCAL_ID + "2", 1835 DATE_TAKEN_MS, 1836 /* count */ 1); 1837 } 1838 } 1839 1840 @Test testGetFavoritesAlbumWithMimeTypesFilter()1841 public void testGetFavoritesAlbumWithMimeTypesFilter() throws Exception { 1842 Cursor localCursor1 = getMediaCursor(LOCAL_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1843 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1844 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 1845 Cursor localCursor2 = getMediaCursor(LOCAL_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1846 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1847 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1848 Cursor cloudCursor1 = getMediaCursor(CLOUD_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1849 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1850 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 1851 Cursor cloudCursor2 = getMediaCursor(CLOUD_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1852 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1853 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1854 1855 try (PickerDbFacade.DbWriteOperation operation = 1856 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 1857 assertWriteOperation(operation, localCursor1, 1); 1858 assertWriteOperation(operation, localCursor2, 1); 1859 operation.setSuccess(); 1860 } 1861 try (PickerDbFacade.DbWriteOperation operation = 1862 mFacade.beginAddMediaOperation(CLOUD_PROVIDER)) { 1863 assertWriteOperation(operation, cloudCursor1, 1); 1864 assertWriteOperation(operation, cloudCursor2, 1); 1865 operation.setSuccess(); 1866 } 1867 1868 PickerDbFacade.QueryFilterBuilder qfb = 1869 new PickerDbFacade.QueryFilterBuilder(/* limit */ 1000); 1870 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 1871 assertWithMessage("Unexpected number of rows on queryMediaForUi without any filter.") 1872 .that(cr.getCount()).isEqualTo(4); 1873 } 1874 1875 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), CLOUD_PROVIDER)) { 1876 assertWithMessage( 1877 "Unexpected number of rows on getMergedAlbums without any filter for cloud " 1878 + "provider.") 1879 .that(cr.getCount()).isEqualTo(2); 1880 cr.moveToFirst(); 1881 assertCloudAlbumCursor(cr, 1882 ALBUM_ID_FAVORITES, 1883 ALBUM_ID_FAVORITES, 1884 LOCAL_ID + "1", 1885 DATE_TAKEN_MS, 1886 /* count */ 2); 1887 cr.moveToNext(); 1888 assertCloudAlbumCursor(cr, 1889 ALBUM_ID_VIDEOS, 1890 ALBUM_ID_VIDEOS, 1891 LOCAL_ID + "1", 1892 DATE_TAKEN_MS, 1893 /* count */ 2); 1894 } 1895 1896 qfb.setMimeTypes(IMAGE_MIME_TYPES_QUERY); 1897 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), /* cloudProvider*/ null)) { 1898 assertWithMessage( 1899 "Unexpected number of rows on getMergedAlbums with mime type filter set to " 1900 + "IMAGE_MIME_TYPES_QUERY and cloudProvider set to null.") 1901 .that(cr.getCount()).isEqualTo(1); 1902 cr.moveToFirst(); 1903 assertCloudAlbumCursor(cr, 1904 ALBUM_ID_FAVORITES, 1905 ALBUM_ID_FAVORITES, 1906 CLOUD_ID + "1", 1907 DATE_TAKEN_MS, 1908 /* count */ 1); 1909 } 1910 1911 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), CLOUD_PROVIDER)) { 1912 assertWithMessage( 1913 "Unexpected number of rows on getMergedAlbums with mime type filter set to " 1914 + "{IMAGE_MIME_TYPES_QUERY} with cloudProvider.") 1915 .that(cr.getCount()).isEqualTo(1); 1916 cr.moveToFirst(); 1917 assertCloudAlbumCursor(cr, 1918 ALBUM_ID_FAVORITES, 1919 ALBUM_ID_FAVORITES, 1920 CLOUD_ID + "1", 1921 DATE_TAKEN_MS, 1922 /* count */ 1); 1923 } 1924 1925 qfb.setMimeTypes(VIDEO_MIME_TYPES_QUERY); 1926 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), CLOUD_PROVIDER)) { 1927 assertWithMessage( 1928 "Unexpected number of rows on getMergedAlbums with mime type filter set to " 1929 + "VIDEO_MIME_TYPES_QUERY with cloudProvider.") 1930 .that(cr.getCount()).isEqualTo(2); 1931 cr.moveToFirst(); 1932 assertCloudAlbumCursor(cr, 1933 ALBUM_ID_FAVORITES, 1934 ALBUM_ID_FAVORITES, 1935 LOCAL_ID + "1", 1936 DATE_TAKEN_MS, 1937 /* count */ 1); 1938 cr.moveToNext(); 1939 assertCloudAlbumCursor(cr, 1940 ALBUM_ID_VIDEOS, 1941 ALBUM_ID_VIDEOS, 1942 LOCAL_ID + "1", 1943 DATE_TAKEN_MS, 1944 /* count */ 2); 1945 } 1946 1947 qfb.setMimeTypes(new String[]{"foo"}); 1948 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), CLOUD_PROVIDER)) { 1949 assertWithMessage( 1950 "Unexpected number of rows on getMergedAlbums with mime type filter set to " 1951 + "{\"foo\"} and not null cloudProvider.") 1952 .that(cr.getCount()).isEqualTo(1); 1953 } 1954 } 1955 1956 @Test testFetchLocalOnly()1957 public void testFetchLocalOnly() throws Exception { 1958 Cursor localCursor1 = getMediaCursor(LOCAL_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1959 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1960 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 1961 Cursor localCursor2 = getMediaCursor(LOCAL_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1962 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1963 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1964 Cursor cloudCursor1 = getMediaCursor(CLOUD_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 1965 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 1966 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 1967 Cursor cloudCursor2 = getMediaCursor(CLOUD_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 1968 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 1969 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 1970 // Item Info: 1971 // 2 items - local - one of them in favorite album 1972 // 2 items - cloud - one in favorite album, one in video album 1973 // Albums Info: 1974 // Videos - Merged Album - 1 Video File (1 cloud) 1975 // Favorites - Merged Album - 2 files (1 local + 1 cloud) 1976 1977 try (PickerDbFacade.DbWriteOperation operation = 1978 mFacade.beginAddMediaOperation(CLOUD_PROVIDER)) { 1979 assertWriteOperation(operation, cloudCursor1, 1); 1980 assertWriteOperation(operation, cloudCursor2, 1); 1981 operation.setSuccess(); 1982 } 1983 try (PickerDbFacade.DbWriteOperation operation = 1984 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 1985 assertWriteOperation(operation, localCursor1, 1); 1986 assertWriteOperation(operation, localCursor2, 1); 1987 operation.setSuccess(); 1988 } 1989 1990 PickerDbFacade.QueryFilterBuilder qfb = 1991 new PickerDbFacade.QueryFilterBuilder(/* limit */ 1000); 1992 // Verify that we see all(local + cloud) items. 1993 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 1994 assertWithMessage("Unexpected number of rows on queryMediaForUi without any filter.") 1995 .that(cr.getCount()).isEqualTo(4); 1996 } 1997 1998 // Verify that we only see local items with isLocalOnly=true 1999 qfb.setIsLocalOnly(true); 2000 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 2001 assertWithMessage( 2002 "Unexpected number of rows on queryMediaForUi with isLocalOnly set to true.") 2003 .that(cr.getCount()).isEqualTo(2); 2004 2005 cr.moveToNext(); 2006 assertWithMessage("Unexpected value of MediaColumns.ID at cursor.") 2007 .that(cr.getString(cr.getColumnIndexOrThrow(MediaColumns.ID))).isEqualTo( 2008 LOCAL_ID + "2"); 2009 cr.moveToNext(); 2010 assertWithMessage("Unexpected value of MediaColumns.ID at cursor.") 2011 .that(cr.getString(cr.getColumnIndexOrThrow(MediaColumns.ID))).isEqualTo( 2012 LOCAL_ID + "1"); 2013 } 2014 2015 // Verify that we see all available merged albums and their respective media count 2016 qfb.setIsLocalOnly(false); 2017 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), CLOUD_PROVIDER)) { 2018 assertWithMessage( 2019 "Unexpected number of rows on getMergedAlbums with isLocalOnly set to false.") 2020 .that(cr.getCount()).isEqualTo(2); 2021 cr.moveToFirst(); 2022 assertCloudAlbumCursor(cr, 2023 ALBUM_ID_FAVORITES, 2024 ALBUM_ID_FAVORITES, 2025 CLOUD_ID + "1", 2026 DATE_TAKEN_MS, 2027 /* count */ 2); 2028 cr.moveToNext(); 2029 assertCloudAlbumCursor(cr, 2030 ALBUM_ID_VIDEOS, 2031 ALBUM_ID_VIDEOS, 2032 CLOUD_ID + "2", 2033 DATE_TAKEN_MS, 2034 /* count */ 1); 2035 } 2036 2037 qfb.setIsLocalOnly(true); 2038 // Verify that with isLocalOnly=true, we only see one album with only one local item. 2039 try (Cursor cr = mFacade.getMergedAlbums(qfb.build(), /* cloudProvider */ null)) { 2040 assertWithMessage( 2041 "Unexpected number of rows on getMergedAlbums with isLocalOnly set to true " 2042 + "and cloudProvider set to null.") 2043 .that(cr.getCount()).isEqualTo(1); 2044 cr.moveToFirst(); 2045 assertCloudAlbumCursor(cr, 2046 ALBUM_ID_FAVORITES, 2047 ALBUM_ID_FAVORITES, 2048 LOCAL_ID + "1", 2049 DATE_TAKEN_MS, 2050 /* count */ 1); 2051 } 2052 } 2053 2054 @Test testFetchItems_withIdSelection()2055 public void testFetchItems_withIdSelection() { 2056 Cursor localCursor1 = getMediaCursor(LOCAL_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 2057 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 2058 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 2059 Cursor localCursor2 = getMediaCursor(LOCAL_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 2060 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 2061 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 2062 Cursor cloudCursor1 = getMediaCursor(CLOUD_ID + "1", DATE_TAKEN_MS, GENERATION_MODIFIED, 2063 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 2064 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 2065 Cursor cloudCursor2 = getMediaCursor(CLOUD_ID + "2", DATE_TAKEN_MS, GENERATION_MODIFIED, 2066 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 2067 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 2068 // Item Info: 2069 // 2 items - local - one of them in favorite album 2070 // 2 items - cloud - one in favorite album, one in video album 2071 // Albums Info: 2072 // Videos - Merged Album - 1 Video File (1 cloud) 2073 // Favorites - Merged Album - 2 files (1 local + 1 cloud) 2074 2075 try (PickerDbFacade.DbWriteOperation operation = 2076 mFacade.beginAddMediaOperation(CLOUD_PROVIDER)) { 2077 assertWriteOperation(operation, cloudCursor1, 1); 2078 assertWriteOperation(operation, cloudCursor2, 1); 2079 operation.setSuccess(); 2080 } 2081 try (PickerDbFacade.DbWriteOperation operation = 2082 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 2083 assertWriteOperation(operation, localCursor1, 1); 2084 assertWriteOperation(operation, localCursor2, 1); 2085 operation.setSuccess(); 2086 } 2087 2088 PickerDbFacade.QueryFilterBuilder qfb = 2089 new PickerDbFacade.QueryFilterBuilder(/* limit */ 1000); 2090 2091 // If mShouldScreenSelectionUris is set and no ids selection items are passed, an empty 2092 // cursor should be returned. 2093 qfb.setShouldScreenSelectionUris(true); 2094 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 2095 assertWithMessage("Unexpected number of rows on queryMediaForUi." 2096 + "No items should have been returned.") 2097 .that(cr.getCount()).isEqualTo(0); 2098 } 2099 2100 // Setting one local id as an input for selection. 2101 // 1 local item should be returned. 2102 qfb.setLocalPreSelectedIds(List.of(LOCAL_ID + "2")); 2103 qfb.setCloudPreSelectionIds(null); 2104 qfb.setShouldScreenSelectionUris(false); 2105 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 2106 assertWithMessage("Unexpected number of rows on queryMediaForUi." 2107 + "Expected number of items is 1.") 2108 .that(cr.getCount()).isEqualTo(1); 2109 cr.moveToNext(); 2110 assertWithMessage("Unexpected value of MediaColumns.ID at cursor.") 2111 .that(cr.getString(cr.getColumnIndex(MediaColumns.ID))).isEqualTo( 2112 LOCAL_ID + "2"); 2113 } 2114 2115 // Setting one cloud id as an input for selection, and disabling local only param. 2116 // 1 cloud item should be returned. 2117 qfb.setIsLocalOnly(false); 2118 qfb.setLocalPreSelectedIds(null); 2119 qfb.setCloudPreSelectionIds(List.of(CLOUD_ID + "1")); 2120 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 2121 assertWithMessage("Unexpected number of rows on queryMediaForUi." 2122 + "Expected number of items is 1.") 2123 .that(cr.getCount()).isEqualTo(1); 2124 cr.moveToNext(); 2125 assertWithMessage("Unexpected value of MediaColumns.ID at cursor.") 2126 .that(cr.getString(cr.getColumnIndex(MediaColumns.ID))).isEqualTo( 2127 CLOUD_ID + "1"); 2128 } 2129 2130 // If local only is enabled and only cloud ids are present, then no items should be 2131 // returned. 2132 qfb.setIsLocalOnly(true); 2133 qfb.setLocalPreSelectedIds(null); 2134 qfb.setCloudPreSelectionIds(List.of(CLOUD_ID + "1")); 2135 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 2136 assertWithMessage("Unexpected number of rows on queryMediaForUi." 2137 + "Expected number of items is 0.") 2138 .that(cr.getCount()).isEqualTo(0); 2139 } 2140 2141 2142 // Setting one local id and one cloud id, 2 items should be returned. 2143 qfb.setIsLocalOnly(false); 2144 qfb.setLocalPreSelectedIds(List.of(LOCAL_ID + "2")); 2145 qfb.setCloudPreSelectionIds(List.of(CLOUD_ID + "1")); 2146 try (Cursor cr = mFacade.queryMediaForUi(qfb.build())) { 2147 assertWithMessage("Unexpected number of rows on queryMediaForUi." 2148 + "Expected number of items is 2.") 2149 .that(cr.getCount()).isEqualTo(2); 2150 cr.moveToNext(); 2151 assertWithMessage("Unexpected value of MediaColumns.ID at cursor.") 2152 .that(cr.getString(cr.getColumnIndex(MediaColumns.ID))).isEqualTo( 2153 LOCAL_ID + "2"); 2154 cr.moveToNext(); 2155 assertWithMessage("Unexpected value of MediaColumns.ID at cursor.") 2156 .that(cr.getString(cr.getColumnIndex(MediaColumns.ID))).isEqualTo( 2157 CLOUD_ID + "1"); 2158 } 2159 } 2160 2161 @Test testDataColumn()2162 public void testDataColumn() throws Exception { 2163 Cursor imageCursor = getMediaCursor(LOCAL_ID, DATE_TAKEN_MS, GENERATION_MODIFIED, 2164 /* mediaStoreUri */ null, SIZE_BYTES, JPEG_IMAGE_MIME_TYPE, 2165 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 2166 Cursor videoCursor = getMediaCursor(LOCAL_ID + 1, DATE_TAKEN_MS, GENERATION_MODIFIED, 2167 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 2168 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ false); 2169 2170 try (PickerDbFacade.DbWriteOperation operation = 2171 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 2172 assertWriteOperation(operation, imageCursor, 1); 2173 assertWriteOperation(operation, videoCursor, 1); 2174 operation.setSuccess(); 2175 } 2176 2177 try (Cursor cr = queryMediaAll(mFacade)) { 2178 assertWithMessage("Unexpected number of rows on queryMediaForUi.") 2179 .that(cr.getCount()).isEqualTo(2); 2180 cr.moveToFirst(); 2181 assertCloudMediaCursor(cr, LOCAL_ID + 1, MP4_VIDEO_MIME_TYPE); 2182 2183 cr.moveToNext(); 2184 assertCloudMediaCursor(cr, LOCAL_ID, JPEG_IMAGE_MIME_TYPE); 2185 } 2186 } 2187 2188 @Test testAddMediaFailure()2189 public void testAddMediaFailure() throws Exception { 2190 try (PickerDbFacade.DbWriteOperation operation = 2191 mFacade.beginAddMediaOperation(CLOUD_PROVIDER)) { 2192 assertThrows(Exception.class, () -> operation.execute(null /* cursor */)); 2193 } 2194 } 2195 2196 @Test testRemoveMediaFailure()2197 public void testRemoveMediaFailure() throws Exception { 2198 try (PickerDbFacade.DbWriteOperation operation = 2199 mFacade.beginRemoveMediaOperation(CLOUD_PROVIDER)) { 2200 assertThrows(Exception.class, () -> operation.execute(null /* cursor */)); 2201 } 2202 } 2203 2204 @Test testUpdateMediaSuccess()2205 public void testUpdateMediaSuccess() throws Exception { 2206 Cursor localCursor = getMediaCursor(LOCAL_ID, DATE_TAKEN_MS, GENERATION_MODIFIED, 2207 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 2208 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 2209 try (PickerDbFacade.DbWriteOperation operation = 2210 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 2211 operation.execute(localCursor); 2212 operation.setSuccess(); 2213 } 2214 2215 try (PickerDbFacade.UpdateMediaOperation operation = 2216 mFacade.beginUpdateMediaOperation(LOCAL_PROVIDER)) { 2217 ContentValues values = new ContentValues(); 2218 values.put(PickerDbFacade.KEY_STANDARD_MIME_TYPE_EXTENSION, 2219 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_ANIMATED_WEBP); 2220 assertWithMessage("Failed to update media with LOCAL_ID.") 2221 .that(operation.execute(LOCAL_ID, values)).isTrue(); 2222 operation.setSuccess(); 2223 } 2224 2225 try (Cursor cursor = queryMediaAll(mFacade)) { 2226 assertWithMessage("Unexpected number of rows after update operation.") 2227 .that(cursor.getCount()).isEqualTo(1); 2228 2229 // Assert that STANDARD_MIME_TYPE_EXTENSION has been updated 2230 cursor.moveToFirst(); 2231 assertWithMessage("Failed to update STANDARD_MIME_TYPE_EXTENSION.") 2232 .that(cursor.getInt(cursor.getColumnIndexOrThrow( 2233 MediaColumns.STANDARD_MIME_TYPE_EXTENSION))) 2234 .isEqualTo(MediaColumns.STANDARD_MIME_TYPE_EXTENSION_ANIMATED_WEBP); 2235 } 2236 } 2237 2238 @Test testUpdateMediaFailure()2239 public void testUpdateMediaFailure() throws Exception { 2240 Cursor localCursor = getMediaCursor(LOCAL_ID, DATE_TAKEN_MS, GENERATION_MODIFIED, 2241 /* mediaStoreUri */ null, SIZE_BYTES, MP4_VIDEO_MIME_TYPE, 2242 STANDARD_MIME_TYPE_EXTENSION, /* isFavorite */ true); 2243 try (PickerDbFacade.DbWriteOperation operation = 2244 mFacade.beginAddMediaOperation(LOCAL_PROVIDER)) { 2245 operation.execute(localCursor); 2246 operation.setSuccess(); 2247 } 2248 2249 try (PickerDbFacade.UpdateMediaOperation operation = 2250 mFacade.beginUpdateMediaOperation(LOCAL_PROVIDER)) { 2251 ContentValues values = new ContentValues(); 2252 values.put(PickerDbFacade.KEY_STANDARD_MIME_TYPE_EXTENSION, 2253 MediaColumns.STANDARD_MIME_TYPE_EXTENSION_ANIMATED_WEBP); 2254 assertWithMessage("Unexpected, should have failed to update media with CLOUD_ID.") 2255 .that(operation.execute(CLOUD_ID, values)).isFalse(); 2256 operation.setSuccess(); 2257 } 2258 2259 try (Cursor cursor = queryMediaAll(mFacade)) { 2260 assertWithMessage("Unexpected number of rows after update operation.") 2261 .that(cursor.getCount()).isEqualTo(1); 2262 2263 // Assert that STANDARD_MIME_TYPE_EXTENSION is same as before 2264 cursor.moveToFirst(); 2265 assertWithMessage("Unexpected STANDARD_MIME_TYPE_EXTENSION, not same as before.") 2266 .that(cursor.getInt(cursor.getColumnIndexOrThrow( 2267 MediaColumns.STANDARD_MIME_TYPE_EXTENSION))) 2268 .isEqualTo(STANDARD_MIME_TYPE_EXTENSION); 2269 } 2270 } 2271 } 2272