1 /* 2 * Copyright (C) 2009 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.email.provider; 18 19 import com.android.email.R; 20 import com.android.email.mail.MessagingException; 21 import com.android.email.mail.store.LocalStore; 22 import com.android.email.provider.AttachmentProvider.AttachmentProviderColumns; 23 import com.android.email.provider.EmailContent.Account; 24 import com.android.email.provider.EmailContent.Attachment; 25 import com.android.email.provider.EmailContent.Mailbox; 26 import com.android.email.provider.EmailContent.Message; 27 28 import android.content.ContentResolver; 29 import android.content.ContentValues; 30 import android.content.Context; 31 import android.content.res.AssetFileDescriptor; 32 import android.database.Cursor; 33 import android.database.sqlite.SQLiteDatabase; 34 import android.graphics.Bitmap; 35 import android.graphics.BitmapFactory; 36 import android.net.Uri; 37 import android.test.ProviderTestCase2; 38 import android.test.mock.MockContentResolver; 39 40 import java.io.File; 41 import java.io.FileNotFoundException; 42 import java.io.FileOutputStream; 43 import java.io.IOException; 44 45 /** 46 * Tests of the Email Attachments provider. 47 * 48 * You can run this entire test case with: 49 * runtest -c com.android.email.provider.AttachmentProviderTests email 50 */ 51 public class AttachmentProviderTests extends ProviderTestCase2<AttachmentProvider> { 52 53 /* 54 * This switch will enable us to transition these tests, and the AttachmentProvider, from the 55 * "old" LocalStore model to the "new" provider model. After the transition is complete, 56 * this flag (and its associated code) can be removed. 57 */ 58 private final boolean USE_LOCALSTORE = false; 59 LocalStore mLocalStore = null; 60 61 EmailProvider mEmailProvider; 62 Context mMockContext; 63 ContentResolver mMockResolver; 64 AttachmentProviderTests()65 public AttachmentProviderTests() { 66 super(AttachmentProvider.class, AttachmentProvider.AUTHORITY); 67 } 68 69 @Override setUp()70 public void setUp() throws Exception { 71 super.setUp(); 72 mMockContext = getMockContext(); 73 mMockResolver = mMockContext.getContentResolver(); 74 75 // Spin up an Email provider as well and put it under the same mock test framework 76 mEmailProvider = new EmailProvider(); 77 mEmailProvider.attachInfo(mMockContext, null); 78 assertNotNull(mEmailProvider); 79 ((MockContentResolver) mMockResolver) 80 .addProvider(EmailProvider.EMAIL_AUTHORITY, mEmailProvider); 81 } 82 83 @Override tearDown()84 public void tearDown() throws Exception { 85 super.tearDown(); 86 87 if (mLocalStore != null) { 88 mLocalStore.delete(); 89 } 90 } 91 92 /** 93 * test delete() - should do nothing 94 * test update() - should do nothing 95 * test insert() - should do nothing 96 */ testUnimplemented()97 public void testUnimplemented() { 98 assertEquals(0, mMockResolver.delete(AttachmentProvider.CONTENT_URI, null, null)); 99 assertEquals(0, mMockResolver.update(AttachmentProvider.CONTENT_URI, null, null, null)); 100 assertEquals(null, mMockResolver.insert(AttachmentProvider.CONTENT_URI, null)); 101 } 102 103 /** 104 * test query() 105 * - item found 106 * - item not found 107 * - permuted projection 108 */ testQuery()109 public void testQuery() throws MessagingException { 110 Account account1 = ProviderTestUtils.setupAccount("attachment-query", false, mMockContext); 111 account1.mCompatibilityUuid = "test-UUID"; 112 account1.save(mMockContext); 113 final long message1Id = 1; 114 long attachment1Id = 1; 115 long attachment2Id = 2; 116 long attachment3Id = 3; 117 118 // Note: There is an implicit assumption in this test sequence that the first 119 // attachment we add will be id=1 and the 2nd will have id=2. This could fail on 120 // a legitimate implementation. Asserts below will catch this and fail the test 121 // if necessary. 122 Uri attachment1Uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment1Id); 123 Uri attachment2Uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment2Id); 124 Uri attachment3Uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment3Id); 125 126 // Test with no attached database - should return null 127 Cursor c = mMockResolver.query(attachment1Uri, (String[])null, null, (String[])null, null); 128 assertNull(c); 129 130 // Test with an attached database, but no attachment found - should return null 131 setupAttachmentDatabase(account1); 132 c = mMockResolver.query(attachment1Uri, (String[])null, null, (String[])null, null); 133 assertNull(c); 134 135 // Add a couple of attachment entries. Note, query() just uses the DB, and does not 136 // sample the files, so we won't bother creating the files 137 Attachment newAttachment1 = ProviderTestUtils.setupAttachment(message1Id, "file1", 100, 138 false, mMockContext); 139 newAttachment1.mContentUri = 140 AttachmentProvider.getAttachmentUri(account1.mId, attachment1Id).toString(); 141 attachment1Id = addAttachmentToDb(account1, newAttachment1); 142 assertEquals("Broken test: Unexpected id assignment", 1, attachment1Id); 143 144 Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message1Id, "file2", 200, 145 false, mMockContext); 146 newAttachment2.mContentUri = 147 AttachmentProvider.getAttachmentUri(account1.mId, attachment2Id).toString(); 148 attachment2Id = addAttachmentToDb(account1, newAttachment2); 149 assertEquals("Broken test: Unexpected id assignment", 2, attachment2Id); 150 151 Attachment newAttachment3 = ProviderTestUtils.setupAttachment(message1Id, "file3", 300, 152 false, mMockContext); 153 newAttachment3.mContentUri = 154 AttachmentProvider.getAttachmentUri(account1.mId, attachment3Id).toString(); 155 attachment3Id = addAttachmentToDb(account1, newAttachment3); 156 assertEquals("Broken test: Unexpected id assignment", 3, attachment3Id); 157 158 // Return a row with all columns specified 159 attachment2Uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment2Id); 160 c = mMockResolver.query( 161 attachment2Uri, 162 new String[] { AttachmentProviderColumns._ID, AttachmentProviderColumns.DATA, 163 AttachmentProviderColumns.DISPLAY_NAME, 164 AttachmentProviderColumns.SIZE }, 165 null, null, null); 166 assertEquals(1, c.getCount()); 167 assertTrue(c.moveToFirst()); 168 assertEquals(attachment2Id, c.getLong(0)); // id 169 assertEquals(attachment2Uri.toString(), c.getString(1)); // content URI 170 assertEquals("file2", c.getString(2)); // display name 171 assertEquals(200, c.getInt(3)); // size 172 173 // Return a row with permuted columns 174 attachment3Uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment3Id); 175 c = mMockResolver.query( 176 attachment3Uri, 177 new String[] { AttachmentProviderColumns.SIZE, 178 AttachmentProviderColumns.DISPLAY_NAME, 179 AttachmentProviderColumns.DATA, AttachmentProviderColumns._ID }, 180 null, null, null); 181 assertEquals(1, c.getCount()); 182 assertTrue(c.moveToFirst()); 183 assertEquals(attachment3Id, c.getLong(3)); // id 184 assertEquals(attachment3Uri.toString(), c.getString(2)); // content URI 185 assertEquals("file3", c.getString(1)); // display name 186 assertEquals(300, c.getInt(0)); // size 187 } 188 189 /** 190 * test getType() 191 * - regular file 192 * - thumbnail 193 */ testGetType()194 public void testGetType() throws MessagingException { 195 Account account1 = ProviderTestUtils.setupAccount("get-type", false, mMockContext); 196 account1.mCompatibilityUuid = "test-UUID"; 197 account1.save(mMockContext); 198 final long message1Id = 1; 199 long attachment1Id = 1; 200 long attachment2Id = 2; 201 long attachment3Id = 3; 202 long attachment4Id = 4; 203 long attachment5Id = 5; 204 long attachment6Id = 6; 205 206 Uri attachment1Uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment1Id); 207 208 // Test with no attached database - should return null 209 String type = mMockResolver.getType(attachment1Uri); 210 assertNull(type); 211 212 // Test with an attached database, but no attachment found - should return null 213 setupAttachmentDatabase(account1); 214 type = mMockResolver.getType(attachment1Uri); 215 assertNull(type); 216 217 // Add a couple of attachment entries. Note, getType() just uses the DB, and does not 218 // sample the files, so we won't bother creating the files 219 Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message1Id, "file2", 100, 220 false, mMockContext); 221 newAttachment2.mMimeType = "image/jpg"; 222 attachment2Id = addAttachmentToDb(account1, newAttachment2); 223 224 Attachment newAttachment3 = ProviderTestUtils.setupAttachment(message1Id, "file3", 100, 225 false, mMockContext); 226 newAttachment3.mMimeType = "text/plain"; 227 attachment3Id = addAttachmentToDb(account1, newAttachment3); 228 229 Attachment newAttachment4 = ProviderTestUtils.setupAttachment(message1Id, "file4.doc", 100, 230 false, mMockContext); 231 newAttachment4.mMimeType = "application/octet-stream"; 232 attachment4Id = addAttachmentToDb(account1, newAttachment4); 233 234 Attachment newAttachment5 = ProviderTestUtils.setupAttachment(message1Id, "file5.xyz", 100, 235 false, mMockContext); 236 newAttachment5.mMimeType = "application/octet-stream"; 237 attachment5Id = addAttachmentToDb(account1, newAttachment5); 238 239 Attachment newAttachment6 = ProviderTestUtils.setupAttachment(message1Id, "file6", 100, 240 false, mMockContext); 241 newAttachment6.mMimeType = ""; 242 attachment6Id = addAttachmentToDb(account1, newAttachment6); 243 244 // Check the returned filetypes 245 Uri uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment2Id); 246 type = mMockResolver.getType(uri); 247 assertEquals("image/jpg", type); 248 uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment3Id); 249 type = mMockResolver.getType(uri); 250 assertEquals("text/plain", type); 251 uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment4Id); 252 type = mMockResolver.getType(uri); 253 assertEquals("application/msword", type); 254 uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment5Id); 255 type = mMockResolver.getType(uri); 256 assertEquals("application/xyz", type); 257 uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment6Id); 258 type = mMockResolver.getType(uri); 259 assertEquals("application/octet-stream", type); 260 261 // Check the returned filetypes for the thumbnails 262 uri = AttachmentProvider.getAttachmentThumbnailUri(account1.mId, attachment2Id, 62, 62); 263 type = mMockResolver.getType(uri); 264 assertEquals("image/png", type); 265 uri = AttachmentProvider.getAttachmentThumbnailUri(account1.mId, attachment3Id, 62, 62); 266 type = mMockResolver.getType(uri); 267 assertEquals("image/png", type); 268 } 269 270 /** 271 * Test static inferMimeType() 272 * From the method doc: 273 * If the given mime type is non-empty and anything other than "application/octet-stream", 274 * just return it. (This is the most common case.) 275 * If the filename has a recognizable extension and it converts to a mime type, return that. 276 * If the filename has an unrecognized extension, return "application/extension" 277 * Otherwise return "application/octet-stream". 278 */ testInferMimeType()279 public void testInferMimeType() { 280 final String DEFAULT = "application/octet-stream"; 281 final String FILE_PDF = "myfile.false.pdf"; 282 final String FILE_ABC = "myfile.false.abc"; 283 final String FILE_NO_EXT = "myfile"; 284 285 // If the given mime type is non-empty and anything other than "application/octet-stream", 286 // just return it. (This is the most common case.) 287 assertEquals("mime/type", AttachmentProvider.inferMimeType(null, "mime/type")); 288 assertEquals("mime/type", AttachmentProvider.inferMimeType("", "mime/type")); 289 assertEquals("mime/type", AttachmentProvider.inferMimeType(FILE_PDF, "mime/type")); 290 291 // If the filename has a recognizable extension and it converts to a mime type, return that. 292 assertEquals("application/pdf", AttachmentProvider.inferMimeType(FILE_PDF, null)); 293 assertEquals("application/pdf", AttachmentProvider.inferMimeType(FILE_PDF, "")); 294 assertEquals("application/pdf", AttachmentProvider.inferMimeType(FILE_PDF, DEFAULT)); 295 296 // If the filename has an unrecognized extension, return "application/extension" 297 assertEquals("application/abc", AttachmentProvider.inferMimeType(FILE_ABC, null)); 298 assertEquals("application/abc", AttachmentProvider.inferMimeType(FILE_ABC, "")); 299 assertEquals("application/abc", AttachmentProvider.inferMimeType(FILE_ABC, DEFAULT)); 300 301 // Otherwise return "application/octet-stream". 302 assertEquals(DEFAULT, AttachmentProvider.inferMimeType(FILE_NO_EXT, null)); 303 assertEquals(DEFAULT, AttachmentProvider.inferMimeType(FILE_NO_EXT, "")); 304 assertEquals(DEFAULT, AttachmentProvider.inferMimeType(FILE_NO_EXT, DEFAULT)); 305 assertEquals(DEFAULT, AttachmentProvider.inferMimeType(null, null)); 306 assertEquals(DEFAULT, AttachmentProvider.inferMimeType("", "")); 307 } 308 309 /** 310 * test openFile() 311 * - regular file 312 * - TODO: variations on the content URI 313 */ testOpenFile()314 public void testOpenFile() throws MessagingException, IOException { 315 Account account1 = ProviderTestUtils.setupAccount("open-file", false, mMockContext); 316 account1.mCompatibilityUuid = "test-UUID"; 317 account1.save(mMockContext); 318 final long message1Id = 1; 319 long attachment1Id = 1; 320 long attachment2Id = 2; 321 322 // Note: There is an implicit assumption in this test sequence that the first 323 // attachment we add will be id=1 and the 2nd will have id=2. This could fail on 324 // a legitimate implementation. Asserts below will catch this and fail the test 325 // if necessary. 326 Uri file1Uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment1Id); 327 Uri file2Uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment2Id); 328 329 // Test with no attached database - should throw an exception 330 AssetFileDescriptor afd; 331 try { 332 afd = mMockResolver.openAssetFileDescriptor(file1Uri, "r"); 333 fail("Should throw an exception on a bad URI"); 334 } catch (FileNotFoundException fnf) { 335 // expected 336 } 337 338 // Test with an attached database, but no attachment found 339 setupAttachmentDatabase(account1); 340 try { 341 afd = mMockResolver.openAssetFileDescriptor(file1Uri, "r"); 342 fail("Should throw an exception on a missing attachment entry"); 343 } catch (FileNotFoundException fnf) { 344 // expected 345 } 346 347 // Add an attachment (but no associated file) 348 Attachment newAttachment = ProviderTestUtils.setupAttachment(message1Id, "file", 100, 349 false, mMockContext); 350 attachment1Id = addAttachmentToDb(account1, newAttachment); 351 assertEquals("Broken test: Unexpected id assignment", 1, attachment1Id); 352 353 // Test with an attached database, attachment entry found, but no attachment found 354 try { 355 afd = mMockResolver.openAssetFileDescriptor(file1Uri, "r"); 356 fail("Should throw an exception on a missing attachment file"); 357 } catch (FileNotFoundException fnf) { 358 // expected 359 } 360 361 // Create an "attachment" by copying an image resource into a file 362 /* String fileName = */ createAttachmentFile(account1, attachment2Id); 363 Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message1Id, "file", 100, 364 false, mMockContext); 365 newAttachment2.mContentId = null; 366 newAttachment2.mContentUri = 367 AttachmentProvider.getAttachmentUri(account1.mId, attachment2Id).toString(); 368 newAttachment2.mMimeType = "image/png"; 369 attachment2Id = addAttachmentToDb(account1, newAttachment2); 370 assertEquals("Broken test: Unexpected id assignment", 2, attachment2Id); 371 372 // Test with an attached database, attachment entry found - returns a file 373 afd = mMockResolver.openAssetFileDescriptor(file2Uri, "r"); 374 assertNotNull(afd); 375 // TODO: Confirm it's the "right" file? 376 afd.close(); 377 } 378 379 /** 380 * test openFile() 381 * - thumbnail 382 * @throws IOException 383 * 384 * TODO: The thumbnail mode returns null for its failure cases (and in one case, throws 385 * an SQLiteException). The ContentResolver contract requires throwing FileNotFoundException 386 * in all of the non-success cases, and the provider should be fixed for consistency. 387 */ testOpenThumbnail()388 public void testOpenThumbnail() throws MessagingException, IOException { 389 Account account1 = ProviderTestUtils.setupAccount("open-thumbnail", false, mMockContext); 390 account1.mCompatibilityUuid = "test-UUID"; 391 account1.save(mMockContext); 392 final long message1Id = 1; 393 long attachment1Id = 1; 394 long attachment2Id = 2; 395 396 // Note: There is an implicit assumption in this test sequence that the first 397 // attachment we add will be id=1 and the 2nd will have id=2. This could fail on 398 // a legitimate implementation. Asserts below will catch this and fail the test 399 // if necessary. 400 Uri thumb1Uri = AttachmentProvider.getAttachmentThumbnailUri(account1.mId, attachment1Id, 401 62, 62); 402 Uri thumb2Uri = AttachmentProvider.getAttachmentThumbnailUri(account1.mId, attachment2Id, 403 62, 62); 404 405 // Test with no attached database - should return null (used to throw SQLiteException) 406 AssetFileDescriptor afd = mMockResolver.openAssetFileDescriptor(thumb1Uri, "r"); 407 assertNull(afd); 408 409 // Test with an attached database, but no attachment found 410 setupAttachmentDatabase(account1); 411 afd = mMockResolver.openAssetFileDescriptor(thumb1Uri, "r"); 412 assertNull(afd); 413 414 // Add an attachment (but no associated file) 415 Attachment newAttachment = ProviderTestUtils.setupAttachment(message1Id, "file", 100, 416 false, mMockContext); 417 attachment1Id = addAttachmentToDb(account1, newAttachment); 418 assertEquals("Broken test: Unexpected id assignment", 1, attachment1Id); 419 420 // Test with an attached database, attachment entry found, but no attachment found 421 afd = mMockResolver.openAssetFileDescriptor(thumb1Uri, "r"); 422 assertNull(afd); 423 424 // Create an "attachment" by copying an image resource into a file 425 /* String fileName = */ createAttachmentFile(account1, attachment2Id); 426 Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message1Id, "file", 100, 427 false, mMockContext); 428 newAttachment2.mContentId = null; 429 newAttachment2.mContentUri = 430 AttachmentProvider.getAttachmentUri(account1.mId, attachment2Id).toString(); 431 newAttachment2.mMimeType = "image/png"; 432 attachment2Id = addAttachmentToDb(account1, newAttachment2); 433 assertEquals("Broken test: Unexpected id assignment", 2, attachment2Id); 434 435 // Test with an attached database, attachment entry found - returns a thumbnail 436 afd = mMockResolver.openAssetFileDescriptor(thumb2Uri, "r"); 437 assertNotNull(afd); 438 // TODO: Confirm it's the "right" file? 439 afd.close(); 440 } 441 createAttachment(Account account, long messageId, String contentUriStr)442 private Uri createAttachment(Account account, long messageId, String contentUriStr) { 443 // Add an attachment entry. 444 Attachment newAttachment = ProviderTestUtils.setupAttachment(messageId, "file", 100, 445 false, mMockContext); 446 newAttachment.mContentUri = contentUriStr; 447 long attachmentId = addAttachmentToDb(account, newAttachment); 448 Uri attachmentUri = AttachmentProvider.getAttachmentUri(account.mId, attachmentId); 449 return attachmentUri; 450 } 451 452 /** 453 * test resolveAttachmentIdToContentUri() 454 * - without DB 455 * - not in DB 456 * - in DB, with not-null contentUri 457 * - in DB, with null contentUri 458 */ testResolveAttachmentIdToContentUri()459 public void testResolveAttachmentIdToContentUri() throws MessagingException { 460 Account account1 = ProviderTestUtils.setupAccount("attachment-query", false, mMockContext); 461 account1.mCompatibilityUuid = "test-UUID"; 462 account1.save(mMockContext); 463 final long message1Id = 1; 464 // We use attachmentId == 1 but any other id would do 465 final long attachment1Id = 1; 466 final Uri attachment1Uri = AttachmentProvider.getAttachmentUri(account1.mId, attachment1Id); 467 468 // Test with no attached database - should return input 469 Uri result = AttachmentProvider.resolveAttachmentIdToContentUri( 470 mMockResolver, attachment1Uri); 471 assertEquals(attachment1Uri, result); 472 473 setupAttachmentDatabase(account1); 474 475 // Test with an attached database, but no attachment found - should return input 476 // We know that the attachmentId 1 does not exist because there are no attachments 477 // created at this point 478 result = AttachmentProvider.resolveAttachmentIdToContentUri( 479 mMockResolver, attachment1Uri); 480 assertEquals(attachment1Uri, result); 481 482 // Test with existing attachement and contentUri != null 483 // Note, resolveAttachmentIdToContentUri() just uses 484 // the DB, and does not sample the files, so we won't bother creating the files 485 { 486 Uri attachmentUri = createAttachment(account1, message1Id, "file:///path/to/file"); 487 Uri contentUri = AttachmentProvider.resolveAttachmentIdToContentUri(mMockResolver, 488 attachmentUri); 489 // When the attachment is found, return the stored content_uri value 490 assertEquals("file:///path/to/file", contentUri.toString()); 491 } 492 493 // Test with existing attachement and contentUri == null 494 { 495 Uri attachmentUri = createAttachment(account1, message1Id, null); 496 Uri contentUri = AttachmentProvider.resolveAttachmentIdToContentUri(mMockResolver, 497 attachmentUri); 498 // When contentUri is null should return input 499 assertEquals(attachmentUri, contentUri); 500 } 501 } 502 503 /** 504 * Test the functionality of deleting all attachment files for a given message. 505 */ testDeleteFiles()506 public void testDeleteFiles() throws IOException { 507 Account account1 = ProviderTestUtils.setupAccount("attachment-query", false, mMockContext); 508 account1.mCompatibilityUuid = "test-UUID"; 509 account1.save(mMockContext); 510 final long message1Id = 1; // 1 attachment, 1 file 511 final long message2Id = 2; // 2 attachments, 2 files 512 final long message3Id = 3; // 1 attachment, missing file 513 final long message4Id = 4; // no attachments 514 515 // Add attachment entries for various test messages 516 Attachment newAttachment1 = ProviderTestUtils.setupAttachment(message1Id, "file1", 100, 517 true, mMockContext); 518 Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message2Id, "file2", 200, 519 true, mMockContext); 520 Attachment newAttachment3 = ProviderTestUtils.setupAttachment(message2Id, "file3", 100, 521 true, mMockContext); 522 Attachment newAttachment4 = ProviderTestUtils.setupAttachment(message3Id, "file4", 100, 523 true, mMockContext); 524 525 // Create test files 526 createAttachmentFile(account1, newAttachment1.mId); 527 createAttachmentFile(account1, newAttachment2.mId); 528 createAttachmentFile(account1, newAttachment3.mId); 529 530 // Confirm 3 attachment files found 531 File attachmentsDir = AttachmentProvider.getAttachmentDirectory(mMockContext, account1.mId); 532 assertEquals(3, attachmentsDir.listFiles().length); 533 534 // Command deletion of some files and check for results 535 536 // Message 4 has no attachments so no files should be deleted 537 AttachmentProvider.deleteAllAttachmentFiles(mMockContext, account1.mId, message4Id); 538 assertEquals(3, attachmentsDir.listFiles().length); 539 540 // Message 3 has no attachment files so no files should be deleted 541 AttachmentProvider.deleteAllAttachmentFiles(mMockContext, account1.mId, message3Id); 542 assertEquals(3, attachmentsDir.listFiles().length); 543 544 // Message 2 has 2 attachment files so this should delete 2 files 545 AttachmentProvider.deleteAllAttachmentFiles(mMockContext, account1.mId, message2Id); 546 assertEquals(1, attachmentsDir.listFiles().length); 547 548 // Message 1 has 1 attachment file so this should delete the last file 549 AttachmentProvider.deleteAllAttachmentFiles(mMockContext, account1.mId, message1Id); 550 assertEquals(0, attachmentsDir.listFiles().length); 551 } 552 553 /** 554 * Test the functionality of deleting an entire mailbox's attachments. 555 */ testDeleteMailbox()556 public void testDeleteMailbox() throws IOException { 557 Account account1 = ProviderTestUtils.setupAccount("attach-mbox-del", false, mMockContext); 558 account1.mCompatibilityUuid = "test-UUID"; 559 account1.save(mMockContext); 560 long account1Id = account1.mId; 561 Mailbox mailbox1 = ProviderTestUtils.setupMailbox("mbox1", account1Id, true, mMockContext); 562 long mailbox1Id = mailbox1.mId; 563 Mailbox mailbox2 = ProviderTestUtils.setupMailbox("mbox2", account1Id, true, mMockContext); 564 long mailbox2Id = mailbox2.mId; 565 566 // two messages per mailbox, one w/attachments, one w/o attachments 567 Message message1a = ProviderTestUtils.setupMessage("msg1a", account1Id, mailbox1Id, false, 568 true, mMockContext); 569 Message message1b = ProviderTestUtils.setupMessage("msg1b", account1Id, mailbox1Id, false, 570 true, mMockContext); 571 Message message2a = ProviderTestUtils.setupMessage("msg2a", account1Id, mailbox2Id, false, 572 true, mMockContext); 573 Message message2b = ProviderTestUtils.setupMessage("msg2b", account1Id, mailbox2Id, false, 574 true, mMockContext); 575 576 // attachments on each of the "a" messages (3 on 1a, 1 on 1b) 577 Attachment newAttachment1 = ProviderTestUtils.setupAttachment(message1a.mId, "file1", 100, 578 true, mMockContext); 579 Attachment newAttachment2 = ProviderTestUtils.setupAttachment(message1a.mId, "file2", 200, 580 true, mMockContext); 581 Attachment newAttachment3 = ProviderTestUtils.setupAttachment(message1a.mId, "file3", 100, 582 true, mMockContext); 583 Attachment newAttachment4 = ProviderTestUtils.setupAttachment(message2a.mId, "file4", 100, 584 true, mMockContext); 585 586 // Create test files 587 createAttachmentFile(account1, newAttachment1.mId); 588 createAttachmentFile(account1, newAttachment2.mId); 589 createAttachmentFile(account1, newAttachment3.mId); 590 createAttachmentFile(account1, newAttachment4.mId); 591 592 // Confirm four attachment files found 593 File attachmentsDir = AttachmentProvider.getAttachmentDirectory(mMockContext, account1.mId); 594 assertEquals(4, attachmentsDir.listFiles().length); 595 596 // Command the deletion of mailbox 1 - we should lose 3 attachment files 597 AttachmentProvider.deleteAllMailboxAttachmentFiles(mMockContext, account1Id, mailbox1Id); 598 assertEquals(1, attachmentsDir.listFiles().length); 599 600 // Command the deletion of mailbox 2 - we should lose 1 attachment file 601 AttachmentProvider.deleteAllMailboxAttachmentFiles(mMockContext, account1Id, mailbox2Id); 602 assertEquals(0, attachmentsDir.listFiles().length); 603 } 604 605 606 /** 607 * Create an attachment by copying an image resource into a file. Uses "real" resources 608 * to get a real image from Email 609 */ createAttachmentFile(Account forAccount, long id)610 private String createAttachmentFile(Account forAccount, long id) throws IOException { 611 File outFile = getAttachmentFile(forAccount, id); 612 Bitmap bitmap = BitmapFactory.decodeResource(getContext().getResources(), 613 R.drawable.ic_email_attachment); 614 FileOutputStream out = new FileOutputStream(outFile); 615 bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); 616 out.close(); 617 618 return outFile.getAbsolutePath(); 619 } 620 621 /** 622 * Set up the attachments database. 623 */ setupAttachmentDatabase(Account forAccount)624 private void setupAttachmentDatabase(Account forAccount) throws MessagingException { 625 if (USE_LOCALSTORE) { 626 String localStoreUri = "local://localhost/" + dbName(forAccount); 627 mLocalStore = (LocalStore) LocalStore.newInstance(localStoreUri, mMockContext, null); 628 } else { 629 // Nothing to do - EmailProvider is already available for us 630 } 631 } 632 633 /** 634 * Record an attachment in the attachments database 635 * @return the id of the attachment just created 636 */ addAttachmentToDb(Account forAccount, Attachment newAttachment)637 private long addAttachmentToDb(Account forAccount, Attachment newAttachment) { 638 long attachmentId = -1; 639 if (USE_LOCALSTORE) { 640 ContentValues cv = new ContentValues(); 641 cv.put("message_id", newAttachment.mMessageKey); 642 cv.put("content_uri", newAttachment.mContentUri); 643 cv.put("store_data", (String)null); 644 cv.put("size", newAttachment.mSize); 645 cv.put("name", newAttachment.mFileName); 646 cv.put("mime_type", newAttachment.mMimeType); 647 cv.put("content_id", newAttachment.mContentId); 648 649 SQLiteDatabase db = null; 650 try { 651 db = SQLiteDatabase.openDatabase(dbName(forAccount), null, 0); 652 attachmentId = db.insertOrThrow("attachments", "message_id", cv); 653 } 654 finally { 655 if (db != null) { 656 db.close(); 657 } 658 } 659 } else { 660 newAttachment.save(mMockContext); 661 attachmentId = newAttachment.mId; 662 } 663 return attachmentId; 664 } 665 666 /** 667 * Return the database path+name for a given account 668 */ dbName(Account forAccount)669 private String dbName(Account forAccount) { 670 if (USE_LOCALSTORE) { 671 return mMockContext.getDatabasePath(forAccount.mCompatibilityUuid + ".db").toString(); 672 } else { 673 throw new java.lang.UnsupportedOperationException(); 674 } 675 } 676 677 /** 678 * Map from account, attachment ID to attachment file 679 */ getAttachmentFile(Account forAccount, long id)680 private File getAttachmentFile(Account forAccount, long id) { 681 String idString = Long.toString(id); 682 if (USE_LOCALSTORE) { 683 return new File(mMockContext.getDatabasePath(forAccount.mCompatibilityUuid + ".db_att"), 684 idString); 685 } else { 686 File attachmentsDir = mMockContext.getDatabasePath(forAccount.mId + ".db_att"); 687 if (!attachmentsDir.exists()) { 688 attachmentsDir.mkdirs(); 689 } 690 return new File(attachmentsDir, idString); 691 } 692 } 693 } 694