EmailProvider.java revision e34525d0f026a7467cee1cb5fddcf25ba6f35207
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 17package com.android.email.provider; 18 19import com.android.email.provider.EmailContent.Account; 20import com.android.email.provider.EmailContent.AccountColumns; 21import com.android.email.provider.EmailContent.Attachment; 22import com.android.email.provider.EmailContent.AttachmentColumns; 23import com.android.email.provider.EmailContent.Body; 24import com.android.email.provider.EmailContent.BodyColumns; 25import com.android.email.provider.EmailContent.HostAuth; 26import com.android.email.provider.EmailContent.HostAuthColumns; 27import com.android.email.provider.EmailContent.Mailbox; 28import com.android.email.provider.EmailContent.MailboxColumns; 29import com.android.email.provider.EmailContent.Message; 30import com.android.email.provider.EmailContent.MessageColumns; 31import com.android.email.provider.EmailContent.SyncColumns; 32 33import android.content.ContentProvider; 34import android.content.ContentProviderOperation; 35import android.content.ContentProviderResult; 36import android.content.ContentUris; 37import android.content.ContentValues; 38import android.content.Context; 39import android.content.OperationApplicationException; 40import android.content.UriMatcher; 41import android.database.Cursor; 42import android.database.SQLException; 43import android.database.sqlite.SQLiteDatabase; 44import android.database.sqlite.SQLiteOpenHelper; 45import android.net.Uri; 46import android.util.Config; 47import android.util.Log; 48 49import java.util.ArrayList; 50 51/* 52 * TODO 53 * 54 * Add Email.Body class and support, now that this is stored separately 55 * Handle deletion cascades (either w/ triggers or code) 56 * 57 */ 58public class EmailProvider extends ContentProvider { 59 60 private static final String TAG = "EmailProvider"; 61 62 static final String DATABASE_NAME = "EmailProvider.db"; 63 static final String BODY_DATABASE_NAME = "EmailProviderBody.db"; 64 65 // In these early versions, updating the database version will cause all tables to be deleted 66 // Obviously, we'll handle upgrades differently once things are a bit stable 67 public static final int DATABASE_VERSION = 12; 68 public static final int BODY_DATABASE_VERSION = 1; 69 70 public static final String EMAIL_AUTHORITY = "com.android.email.provider"; 71 72 private static final int ACCOUNT_BASE = 0; 73 private static final int ACCOUNT = ACCOUNT_BASE; 74 private static final int ACCOUNT_MAILBOXES = ACCOUNT_BASE + 1; 75 private static final int ACCOUNT_ID = ACCOUNT_BASE + 2; 76 77 private static final int MAILBOX_BASE = 0x1000; 78 private static final int MAILBOX = MAILBOX_BASE; 79 private static final int MAILBOX_MESSAGES = MAILBOX_BASE + 1; 80 private static final int MAILBOX_ID = MAILBOX_BASE + 2; 81 82 private static final int MESSAGE_BASE = 0x2000; 83 private static final int MESSAGE = MESSAGE_BASE; 84 private static final int MESSAGE_ATTACHMENTS = MESSAGE_BASE + 1; 85 private static final int MESSAGE_ID = MESSAGE_BASE + 2; 86 87 private static final int ATTACHMENT_BASE = 0x3000; 88 private static final int ATTACHMENT = ATTACHMENT_BASE; 89 private static final int ATTACHMENT_CONTENT = ATTACHMENT_BASE + 1; 90 private static final int ATTACHMENT_ID = ATTACHMENT_BASE + 2; 91 92 // TEMPORARY UNTIL ACCOUNT MANAGER CAN BE USED 93 private static final int HOSTAUTH_BASE = 0x4000; 94 private static final int HOSTAUTH = HOSTAUTH_BASE; 95 private static final int HOSTAUTH_ID = HOSTAUTH_BASE + 1; 96 97 private static final int UPDATED_MESSAGE_BASE = 0x5000; 98 private static final int UPDATED_MESSAGE = UPDATED_MESSAGE_BASE; 99 private static final int UPDATED_MESSAGE_ATTACHMENTS = UPDATED_MESSAGE_BASE + 1; 100 private static final int UPDATED_MESSAGE_ID = UPDATED_MESSAGE_BASE + 2; 101 102 // BODY_BASE MAY BE CHANGED BUT IT MUST BE HIGHEST BASE VALUE (it's in a different database!) 103 private static final int BODY_BASE = 0x6000; 104 private static final int BODY = BODY_BASE; 105 private static final int BODY_ID = BODY_BASE + 1; 106 private static final int BODY_HTML = BODY_BASE + 2; 107 private static final int BODY_TEXT = BODY_BASE + 4; 108 109 110 private static final int BASE_SHIFT = 12; // 12 bits to the base type: 0, 0x1000, 0x2000, etc. 111 112 private static final String[] TABLE_NAMES = { 113 EmailContent.Account.TABLE_NAME, 114 EmailContent.Mailbox.TABLE_NAME, 115 EmailContent.Message.TABLE_NAME, 116 EmailContent.Attachment.TABLE_NAME, 117 EmailContent.HostAuth.TABLE_NAME, 118 EmailContent.Message.UPDATES_TABLE_NAME, 119 EmailContent.Body.TABLE_NAME 120 }; 121 122 private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH); 123 124 static { 125 // Email URI matching table 126 UriMatcher matcher = sURIMatcher; 127 // All accounts 128 matcher.addURI(EMAIL_AUTHORITY, "account", ACCOUNT); // IMPLEMENTED 129 // A specific account 130 // insert into this URI causes a mailbox to be added to the account 131 matcher.addURI(EMAIL_AUTHORITY, "account/#", ACCOUNT_ID); // IMPLEMENTED 132 // The mailboxes in a specific account 133 matcher.addURI(EMAIL_AUTHORITY, "account/#/mailbox", ACCOUNT_MAILBOXES); 134 // All mailboxes 135 matcher.addURI(EMAIL_AUTHORITY, "mailbox", MAILBOX); // IMPLEMENTED 136 // A specific mailbox 137 // insert into this URI causes a message to be added to the mailbox 138 // ** NOTE For now, the accountKey must be set manually in the values! 139 matcher.addURI(EMAIL_AUTHORITY, "mailbox/#", MAILBOX_ID); // IMPLEMENTED 140 // The messages in a specific mailbox 141 matcher.addURI(EMAIL_AUTHORITY, "mailbox/#/message", MAILBOX_MESSAGES); 142 // All messages 143 matcher.addURI(EMAIL_AUTHORITY, "message", MESSAGE); // IMPLEMENTED 144 // A specific message 145 // insert into this URI causes an attachment to be added to the message 146 matcher.addURI(EMAIL_AUTHORITY, "message/#", MESSAGE_ID); // IMPLEMENTED 147 // The attachments of a specific message 148 matcher.addURI(EMAIL_AUTHORITY, "message/#/attachment", MESSAGE_ATTACHMENTS); // IMPLEMENTED 149 // All updated messages 150 matcher.addURI(EMAIL_AUTHORITY, "updatedMessage", UPDATED_MESSAGE); // IMPLEMENTED 151 // A specific updated message 152 matcher.addURI(EMAIL_AUTHORITY, "updatedMessage/#", UPDATED_MESSAGE_ID); // IMPLEMENTED 153 // The attachments of a specific updated message 154 matcher.addURI(EMAIL_AUTHORITY, "updatedMessage/#/attachment", UPDATED_MESSAGE_ATTACHMENTS); 155 // A specific attachment 156 matcher.addURI(EMAIL_AUTHORITY, "attachment", ATTACHMENT); // IMPLEMENTED 157 // A specific attachment (the header information) 158 matcher.addURI(EMAIL_AUTHORITY, "attachment/#", ATTACHMENT_ID); // IMPLEMENTED 159 // The content for a specific attachment 160 matcher.addURI(EMAIL_AUTHORITY, "attachment/content/*", ATTACHMENT_CONTENT); 161 162 // All mail bodies 163 matcher.addURI(EMAIL_AUTHORITY, "body", BODY); 164 // A specific mail body 165 matcher.addURI(EMAIL_AUTHORITY, "body/#", BODY_ID); 166 // The HTML part of a specific mail body 167 matcher.addURI(EMAIL_AUTHORITY, "body/#/html", BODY_HTML); 168 // The plain text part of a specific mail body 169 matcher.addURI(EMAIL_AUTHORITY, "body/#/text", BODY_TEXT); 170 171 // A specific attachment 172 matcher.addURI(EMAIL_AUTHORITY, "hostauth", HOSTAUTH); // IMPLEMENTED 173 // A specific attachment (the header information) 174 matcher.addURI(EMAIL_AUTHORITY, "hostauth/#", HOSTAUTH_ID); // IMPLEMENTED 175 176 } 177 178 static void createMessageTable(SQLiteDatabase db) { 179 String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " 180 + SyncColumns.ACCOUNT_KEY + " integer, " 181 + SyncColumns.SERVER_ID + " integer, " 182 + SyncColumns.SERVER_VERSION + " integer, " 183 + SyncColumns.DATA + " text, " 184 + SyncColumns.DIRTY_COUNT + " integer, " 185 + MessageColumns.DISPLAY_NAME + " text, " 186 + MessageColumns.TIMESTAMP + " integer, " 187 + MessageColumns.SUBJECT + " text, " 188 + MessageColumns.PREVIEW + " text, " 189 + MessageColumns.FLAG_READ + " integer, " 190 + MessageColumns.FLAG_LOADED + " integer, " 191 + MessageColumns.FLAG_FAVORITE + " integer, " 192 + MessageColumns.FLAG_ATTACHMENT + " integer, " 193 + MessageColumns.FLAGS + " integer, " 194 + MessageColumns.TEXT_INFO + " text, " 195 + MessageColumns.HTML_INFO + " text, " 196 + MessageColumns.CLIENT_ID + " integer, " 197 + MessageColumns.MESSAGE_ID + " text, " 198 + MessageColumns.THREAD_ID + " text, " 199 + MessageColumns.BODY_ID + " integer, " 200 + MessageColumns.MAILBOX_KEY + " integer, " 201 + MessageColumns.ACCOUNT_KEY + " integer, " 202 + MessageColumns.REFERENCE_KEY + " integer, " 203 + MessageColumns.SENDER_LIST + " text, " 204 + MessageColumns.FROM_LIST + " text, " 205 + MessageColumns.TO_LIST + " text, " 206 + MessageColumns.CC_LIST + " text, " 207 + MessageColumns.BCC_LIST + " text, " 208 + MessageColumns.REPLY_TO_LIST + " text" 209 + ");"; 210 db.execSQL("create table " + Message.TABLE_NAME + s); 211 db.execSQL("create table " + Message.UPDATES_TABLE_NAME + s); 212 db.execSQL("create index message_" + MessageColumns.TIMESTAMP 213 + " on " + Message.TABLE_NAME + " (" + MessageColumns.TIMESTAMP + ");"); 214 db.execSQL("create index message_" + MessageColumns.FLAG_READ 215 + " on " + Message.TABLE_NAME + " (" + MessageColumns.FLAG_READ + ");"); 216 db.execSQL("create index message_" + MessageColumns.FLAG_LOADED 217 + " on " + Message.TABLE_NAME + " (" + MessageColumns.FLAG_LOADED + ");"); 218 db.execSQL("create index message_" + MessageColumns.MAILBOX_KEY 219 + " on " + Message.TABLE_NAME + " (" + MessageColumns.MAILBOX_KEY + ");"); 220 db.execSQL("create index message_" + SyncColumns.SERVER_ID 221 + " on " + Message.TABLE_NAME + " (" + SyncColumns.SERVER_ID + ");"); 222 223 // When a record is FIRST updated, copy the original data into the updates table 224 // Server version not null tells us that this is synced back to the server 225 // The sync engine can determine what needs to go up to the server 226 db.execSQL("CREATE TRIGGER message_update UPDATE ON " + Message.TABLE_NAME + 227 " WHEN old." + SyncColumns.DIRTY_COUNT + "=0 AND new." + SyncColumns.DIRTY_COUNT + 228 "!=0 AND old." + SyncColumns.SERVER_VERSION + " IS NOT NULL " + 229 "BEGIN INSERT INTO " + Message.UPDATES_TABLE_NAME + 230 " SELECT * FROM message WHERE " + 231 EmailContent.RECORD_ID + "=old." + EmailContent.RECORD_ID + ";END"); 232 233 // Deleted records are automatically copied into updates table 234 // TODO How will the sync adapter know that these records are deletions? 235 // Answer: WeDo we may have to use an EXCEPT clause, as in 236 // SELECT id from Message_Update where mailboxKey=n EXCEPT SELECT id from Message? 237 db.execSQL("CREATE TRIGGER message_delete BEFORE DELETE ON " + Message.TABLE_NAME + 238 " BEGIN INSERT INTO " + Message.UPDATES_TABLE_NAME + 239 " SELECT * FROM message WHERE " + EmailContent.RECORD_ID + 240 "=old." + EmailContent.RECORD_ID + ";END"); 241 } 242 243 static void upgradeMessageTable(SQLiteDatabase db, int oldVersion, int newVersion) { 244 db.execSQL("drop table " + Message.TABLE_NAME); 245 db.execSQL("drop table " + Message.UPDATES_TABLE_NAME); 246 createMessageTable(db); 247 } 248 249 static void createAccountTable(SQLiteDatabase db) { 250 String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " 251 + AccountColumns.DISPLAY_NAME + " text, " 252 + AccountColumns.EMAIL_ADDRESS + " text, " 253 + AccountColumns.SYNC_KEY + " text, " 254 + AccountColumns.SYNC_LOOKBACK + " integer, " 255 + AccountColumns.SYNC_FREQUENCY + " text, " 256 + AccountColumns.HOST_AUTH_KEY_RECV + " integer, " 257 + AccountColumns.HOST_AUTH_KEY_SEND + " integer, " 258 + AccountColumns.FLAGS + " integer, " 259 + AccountColumns.IS_DEFAULT + " integer, " 260 + AccountColumns.COMPATIBILITY_UUID + " text, " 261 + AccountColumns.SENDER_NAME + " text, " 262 + AccountColumns.RINGTONE_URI + " text " 263 + ");"; 264 db.execSQL("create table " + Account.TABLE_NAME + s); 265 } 266 267 static void upgradeAccountTable(SQLiteDatabase db, int oldVersion, int newVersion) { 268 try { 269 db.execSQL("drop table " + Account.TABLE_NAME); 270 } catch (SQLException e) { 271 } 272 createAccountTable(db); 273 } 274 275 static void createHostAuthTable(SQLiteDatabase db) { 276 String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " 277 + HostAuthColumns.PROTOCOL + " text, " 278 + HostAuthColumns.ADDRESS + " text, " 279 + HostAuthColumns.PORT + " integer, " 280 + HostAuthColumns.FLAGS + " integer, " 281 + HostAuthColumns.LOGIN + " text, " 282 + HostAuthColumns.PASSWORD + " text, " 283 + HostAuthColumns.DOMAIN + " text, " 284 + HostAuthColumns.ACCOUNT_KEY + " integer" 285 + ");"; 286 db.execSQL("create table " + HostAuth.TABLE_NAME + s); 287 } 288 289 static void upgradeHostAuthTable(SQLiteDatabase db, int oldVersion, int newVersion) { 290 try { 291 db.execSQL("drop table " + HostAuth.TABLE_NAME); 292 } catch (SQLException e) { 293 } 294 createHostAuthTable(db); 295 } 296 297 static void createMailboxTable(SQLiteDatabase db) { 298 String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " 299 + MailboxColumns.DISPLAY_NAME + " text, " 300 + MailboxColumns.SERVER_ID + " text, " 301 + MailboxColumns.PARENT_SERVER_ID + " text, " 302 + MailboxColumns.ACCOUNT_KEY + " integer, " 303 + MailboxColumns.TYPE + " integer, " 304 + MailboxColumns.DELIMITER + " integer, " 305 + MailboxColumns.SYNC_KEY + " text, " 306 + MailboxColumns.SYNC_LOOKBACK + " integer, " 307 + MailboxColumns.SYNC_FREQUENCY+ " integer, " 308 + MailboxColumns.SYNC_TIME + " integer, " 309 + MailboxColumns.UNREAD_COUNT + " integer, " 310 + MailboxColumns.FLAG_VISIBLE + " integer, " 311 + MailboxColumns.FLAGS + " integer, " 312 + MailboxColumns.VISIBLE_LIMIT + " integer" 313 + ");"; 314 db.execSQL("create table " + Mailbox.TABLE_NAME + s); 315 db.execSQL("create index mailbox_" + MailboxColumns.SERVER_ID 316 + " on " + Mailbox.TABLE_NAME + " (" + MailboxColumns.SERVER_ID + ")"); 317 db.execSQL("create index mailbox_" + MailboxColumns.ACCOUNT_KEY 318 + " on " + Mailbox.TABLE_NAME + " (" + MailboxColumns.ACCOUNT_KEY + ")"); 319 320 } 321 322 static void upgradeMailboxTable(SQLiteDatabase db, int oldVersion, int newVersion) { 323 try { 324 db.execSQL("drop table " + Mailbox.TABLE_NAME); 325 } catch (SQLException e) { 326 } 327 createMailboxTable(db); 328 } 329 330 static void createAttachmentTable(SQLiteDatabase db) { 331 String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " 332 + AttachmentColumns.FILENAME + " text, " 333 + AttachmentColumns.MIME_TYPE + " text, " 334 + AttachmentColumns.SIZE + " integer, " 335 + AttachmentColumns.CONTENT_ID + " text, " 336 + AttachmentColumns.CONTENT_URI + " text, " 337 + AttachmentColumns.MESSAGE_KEY + " integer, " 338 + AttachmentColumns.LOCATION + " text, " 339 + AttachmentColumns.ENCODING + " text" 340 + ");"; 341 db.execSQL("create table " + Attachment.TABLE_NAME + s); 342 } 343 344 static void upgradeAttachmentTable(SQLiteDatabase db, int oldVersion, int newVersion) { 345 try { 346 db.execSQL("drop table " + Attachment.TABLE_NAME); 347 } catch (SQLException e) { 348 } 349 createAttachmentTable(db); 350 } 351 352 static void createBodyTable(SQLiteDatabase db) { 353 String s = " (" + EmailContent.RECORD_ID + " integer primary key autoincrement, " 354 + BodyColumns.MESSAGE_KEY + " integer, " 355 + BodyColumns.HTML_CONTENT + " text, " 356 + BodyColumns.TEXT_CONTENT + " text" 357 + ");"; 358 db.execSQL("create table " + Body.TABLE_NAME + s); 359 } 360 361 static void upgradeBodyTable(SQLiteDatabase db, int oldVersion, int newVersion) { 362 db.execSQL("drop table " + Body.TABLE_NAME); 363 createBodyTable(db); 364 } 365 366 367 368 private final int mDatabaseVersion = DATABASE_VERSION; 369 private final int mBodyDatabaseVersion = BODY_DATABASE_VERSION; 370 371 private SQLiteDatabase mDatabase; 372 private SQLiteDatabase mBodyDatabase; 373 374 public SQLiteDatabase getDatabase(Context context) { 375 if (mDatabase != null) { 376 return mDatabase; 377 } 378 DatabaseHelper helper = new DatabaseHelper(context, DATABASE_NAME); 379 mDatabase = helper.getWritableDatabase(); 380 if (mDatabase != null) { 381 mDatabase.setLockingEnabled(true); 382 } 383 return mDatabase; 384 } 385 386 public SQLiteDatabase getBodyDatabase(Context context) { 387 if (mBodyDatabase != null) { 388 return mBodyDatabase; 389 } 390 BodyDatabaseHelper helper = new BodyDatabaseHelper(context, BODY_DATABASE_NAME); 391 mBodyDatabase = helper.getWritableDatabase(); 392 if (mBodyDatabase != null) { 393 mBodyDatabase.setLockingEnabled(true); 394 } 395 return mBodyDatabase; 396 } 397 398 private class BodyDatabaseHelper extends SQLiteOpenHelper { 399 BodyDatabaseHelper(Context context, String name) { 400 super(context, name, null, mBodyDatabaseVersion); 401 } 402 403 @Override 404 public void onCreate(SQLiteDatabase db) { 405 // Create all tables here; each class has its own method 406 createBodyTable(db); 407 } 408 409 @Override 410 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 411 upgradeBodyTable(db, oldVersion, newVersion); 412 } 413 414 @Override 415 public void onOpen(SQLiteDatabase db) { 416 } 417 } 418 419 private class DatabaseHelper extends SQLiteOpenHelper { 420 DatabaseHelper(Context context, String name) { 421 super(context, name, null, mDatabaseVersion); 422 } 423 424 @Override 425 public void onCreate(SQLiteDatabase db) { 426 // Create all tables here; each class has its own method 427 createMessageTable(db); 428 createAttachmentTable(db); 429 createMailboxTable(db); 430 createHostAuthTable(db); 431 createAccountTable(db); 432 } 433 434 @Override 435 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 436 upgradeMessageTable(db, oldVersion, newVersion); 437 upgradeAttachmentTable(db, oldVersion, newVersion); 438 upgradeMailboxTable(db, oldVersion, newVersion); 439 upgradeHostAuthTable(db, oldVersion, newVersion); 440 upgradeAccountTable(db, oldVersion, newVersion); 441 } 442 443 @Override 444 public void onOpen(SQLiteDatabase db) { 445 } 446 } 447 448 @Override 449 public int delete(Uri uri, String selection, String[] selectionArgs) { 450 int match = sURIMatcher.match(uri); 451 Context context = getContext(); 452 SQLiteDatabase db = (match >= BODY_BASE) ? getBodyDatabase(context) : getDatabase(context); 453 int table = match >> BASE_SHIFT; 454 String id; 455 456 if (Config.LOGV) { 457 Log.v(TAG, "EmailProvider.delete: uri=" + uri + ", match is " + match); 458 } 459 460 int result; 461 switch (match) { 462 case BODY_ID: 463 case MESSAGE_ID: 464 case UPDATED_MESSAGE_ID: 465 case ATTACHMENT_ID: 466 case MAILBOX_ID: 467 case ACCOUNT_ID: 468 case HOSTAUTH_ID: 469 id = uri.getPathSegments().get(1); 470 result = db.delete(TABLE_NAMES[table], whereWithId(id, selection), selectionArgs); 471 break; 472 case BODY: 473 case MESSAGE: 474 case UPDATED_MESSAGE: 475 case ATTACHMENT: 476 case MAILBOX: 477 case ACCOUNT: 478 case HOSTAUTH: 479 result = db.delete(TABLE_NAMES[table], selection, selectionArgs); 480 break; 481 default: 482 throw new IllegalArgumentException("Unknown URI " + uri); 483 } 484 485 getContext().getContentResolver().notifyChange(uri, null); 486 return result; 487 } 488 489 @Override 490 // Use the email- prefix because message, mailbox, and account are so generic (e.g. SMS, IM) 491 public String getType(Uri uri) { 492 int match = sURIMatcher.match(uri); 493 switch (match) { 494 case BODY_ID: 495 return "vnd.android.cursor.item/email-body"; 496 case BODY: 497 return "vnd.android.cursor.dir/email-message"; 498 case UPDATED_MESSAGE_ID: 499 case MESSAGE_ID: 500 return "vnd.android.cursor.item/email-message"; 501 case MAILBOX_MESSAGES: 502 case UPDATED_MESSAGE: 503 case MESSAGE: 504 return "vnd.android.cursor.dir/email-message"; 505 case ACCOUNT_MAILBOXES: 506 case MAILBOX: 507 return "vnd.android.cursor.dir/email-mailbox"; 508 case MAILBOX_ID: 509 return "vnd.android.cursor.item/email-mailbox"; 510 case ACCOUNT: 511 return "vnd.android.cursor.dir/email-account"; 512 case ACCOUNT_ID: 513 return "vnd.android.cursor.item/email-account"; 514 case MESSAGE_ATTACHMENTS: 515 case ATTACHMENT: 516 return "vnd.android.cursor.dir/email-attachment"; 517 case ATTACHMENT_ID: 518 return "vnd.android.cursor.item/email-attachment"; 519 case HOSTAUTH: 520 return "vnd.android.cursor.dir/email-hostauth"; 521 case HOSTAUTH_ID: 522 return "vnd.android.cursor.item/email-hostauth"; 523 default: 524 throw new IllegalArgumentException("Unknown URI " + uri); 525 } 526 } 527 528 @Override 529 public Uri insert(Uri uri, ContentValues values) { 530 int match = sURIMatcher.match(uri); 531 Context context = getContext(); 532 SQLiteDatabase db = (match >= BODY_BASE) ? getBodyDatabase(context) : getDatabase(context); 533 int table = match >> BASE_SHIFT; 534 long id; 535 536 if (Config.LOGV) { 537 Log.v(TAG, "EmailProvider.insert: uri=" + uri + ", match is " + match); 538 } 539 540 Uri resultUri = null; 541 542 switch (match) { 543 case BODY: 544 case MESSAGE: 545 case ATTACHMENT: 546 case MAILBOX: 547 case ACCOUNT: 548 case HOSTAUTH: 549 // Make sure all new message records have dirty count of 0 550 if (match == MESSAGE) { 551 values.put(SyncColumns.DIRTY_COUNT, 0); 552 } 553 id = db.insert(TABLE_NAMES[table], "foo", values); 554 resultUri = ContentUris.withAppendedId(uri, id); 555 break; 556 case MAILBOX_ID: 557 // This implies adding a message to a mailbox 558 // Hmm, one problem here is that we can't link the account as well, so it must be 559 // already in the values... 560 id = Long.parseLong(uri.getPathSegments().get(1)); 561 values.put(MessageColumns.MAILBOX_KEY, id); 562 resultUri = insert(Message.CONTENT_URI, values); 563 break; 564 case MESSAGE_ID: 565 // This implies adding an attachment to a message. 566 id = Long.parseLong(uri.getPathSegments().get(1)); 567 values.put(AttachmentColumns.MESSAGE_KEY, id); 568 resultUri = insert(Attachment.CONTENT_URI, values); 569 break; 570 case ACCOUNT_ID: 571 // This implies adding a mailbox to an account. 572 id = Long.parseLong(uri.getPathSegments().get(1)); 573 values.put(MailboxColumns.ACCOUNT_KEY, id); 574 resultUri = insert(Mailbox.CONTENT_URI, values); 575 break; 576 case MESSAGE_ATTACHMENTS: 577 id = db.insert(TABLE_NAMES[table], "foo", values); 578 resultUri = ContentUris.withAppendedId(Attachment.CONTENT_URI, id); 579 break; 580 default: 581 throw new IllegalArgumentException("Unknown URL " + uri); 582 } 583 584 // Notify with the base uri, not the new uri (nobody is watching a new record) 585 getContext().getContentResolver().notifyChange(uri, null); 586 return resultUri; 587 } 588 589 @Override 590 public boolean onCreate() { 591 // TODO Auto-generated method stub 592 return false; 593 } 594 595 @Override 596 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 597 String sortOrder) { 598 Cursor c = null; 599 Uri notificationUri = EmailContent.CONTENT_URI; 600 int match = sURIMatcher.match(uri); 601 Context context = getContext(); 602 SQLiteDatabase db = (match >= BODY_BASE) ? getBodyDatabase(context) : getDatabase(context); 603 int table = match >> BASE_SHIFT; 604 String id; 605 606 if (Config.LOGV) { 607 Log.v(TAG, "EmailProvider.query: uri=" + uri + ", match is " + match); 608 } 609 610 switch (match) { 611 case BODY: 612 case MESSAGE: 613 case UPDATED_MESSAGE: 614 case ATTACHMENT: 615 case MAILBOX: 616 case ACCOUNT: 617 case HOSTAUTH: 618 c = db.query(TABLE_NAMES[table], projection, 619 selection, selectionArgs, null, null, sortOrder); 620 break; 621 case BODY_ID: 622 case MESSAGE_ID: 623 case UPDATED_MESSAGE_ID: 624 case ATTACHMENT_ID: 625 case MAILBOX_ID: 626 case ACCOUNT_ID: 627 case HOSTAUTH_ID: 628 id = uri.getPathSegments().get(1); 629 c = db.query(TABLE_NAMES[table], projection, 630 whereWithId(id, selection), selectionArgs, null, null, sortOrder); 631 break; 632 case MESSAGE_ATTACHMENTS: 633 // All attachments for the given message 634 id = uri.getPathSegments().get(1); 635 c = db.query(Attachment.TABLE_NAME, projection, 636 whereWith(Attachment.MESSAGE_KEY + "=" + id, selection), 637 selectionArgs, null, null, sortOrder); 638 break; 639 default: 640 throw new IllegalArgumentException("Unknown URI " + uri); 641 } 642 643 if ((c != null) && !isTemporary()) { 644 c.setNotificationUri(getContext().getContentResolver(), notificationUri); 645 } 646 return c; 647 } 648 649 private String whereWithId(String id, String selection) { 650 StringBuilder sb = new StringBuilder(256); 651 sb.append("_id="); 652 sb.append(id); 653 if (selection != null) { 654 sb.append(" AND "); 655 sb.append(selection); 656 } 657 return sb.toString(); 658 } 659 660 private String whereWith(String where, String selection) { 661 StringBuilder sb = new StringBuilder(where); 662 if (selection != null) { 663 sb.append(" AND "); 664 sb.append(selection); 665 } 666 return sb.toString(); 667 } 668 669 @Override 670 public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 671 int match = sURIMatcher.match(uri); 672 Context context = getContext(); 673 SQLiteDatabase db = (match >= BODY_BASE) ? getBodyDatabase(context) : getDatabase(context); 674 int table = match >> BASE_SHIFT; 675 if (Config.LOGV) { 676 Log.v(TAG, "EmailProvider.update: uri=" + uri + ", match is " + match); 677 } 678 679 int result; 680 681 // Set the dirty bit for messages 682 if ((match == MESSAGE_ID || match == MESSAGE) 683 && values.get(SyncColumns.DIRTY_COUNT) == null) { 684 values.put(SyncColumns.DIRTY_COUNT, 1); 685 } 686 687 switch (match) { 688 case BODY_ID: 689 case MESSAGE_ID: 690 case UPDATED_MESSAGE_ID: 691 case ATTACHMENT_ID: 692 case MAILBOX_ID: 693 case ACCOUNT_ID: 694 case HOSTAUTH_ID: 695 String id = uri.getPathSegments().get(1); 696 // Set dirty if nobody is setting this manually 697 result = db.update(TABLE_NAMES[table], values, whereWithId(id, selection), 698 selectionArgs); 699 break; 700 case BODY: 701 case MESSAGE: 702 case UPDATED_MESSAGE: 703 case ATTACHMENT: 704 case MAILBOX: 705 case ACCOUNT: 706 case HOSTAUTH: 707 result = db.update(TABLE_NAMES[table], values, selection, selectionArgs); 708 break; 709 default: 710 throw new IllegalArgumentException("Unknown URI " + uri); 711 } 712 713 getContext().getContentResolver().notifyChange(uri, null); 714 return result; 715 } 716 717 /* (non-Javadoc) 718 * @see android.content.ContentProvider#applyBatch(android.content.ContentProviderOperation) 719 * 720 * TODO: How do we call notifyChange() or do we need to - does this call the various 721 * update/insert/delete calls? 722 */ 723 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 724 throws OperationApplicationException { 725 SQLiteDatabase db = getDatabase(getContext()); 726 db.beginTransaction(); 727 try { 728 ContentProviderResult[] results = super.applyBatch(operations); 729 db.setTransactionSuccessful(); 730 return results; 731 } finally { 732 db.endTransaction(); 733 } 734 } 735} 736