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