Account.java revision 69c8dd4ba4b62c407dc6e22c4dfe1b0213cbdd20
1/** 2 * Copyright (c) 2012, Google Inc. 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.mail.providers; 18 19import android.content.ContentValues; 20import android.database.Cursor; 21import android.database.MatrixCursor; 22import android.net.Uri; 23import android.os.Parcel; 24import android.os.Parcelable; 25import android.text.TextUtils; 26 27import com.android.mail.content.CursorCreator; 28import com.android.mail.content.ObjectCursor; 29import com.android.mail.providers.UIProvider.AccountCapabilities; 30import com.android.mail.providers.UIProvider.AccountColumns; 31import com.android.mail.providers.UIProvider.SyncStatus; 32import com.android.mail.utils.LogTag; 33import com.android.mail.utils.LogUtils; 34import com.android.mail.utils.Utils; 35import com.google.common.base.Objects; 36import com.google.common.collect.Lists; 37 38import org.json.JSONArray; 39import org.json.JSONException; 40import org.json.JSONObject; 41 42import java.util.HashMap; 43import java.util.List; 44import java.util.Map; 45 46public class Account extends android.accounts.Account implements Parcelable { 47 private static final String SETTINGS_KEY = "settings"; 48 49 /** 50 * The version of the UI provider schema from which this account provider 51 * will return results. 52 */ 53 public final int providerVersion; 54 55 /** 56 * The uri to directly access the information for this account. 57 */ 58 public final Uri uri; 59 60 /** 61 * The possible capabilities that this account supports. 62 */ 63 public final int capabilities; 64 65 /** 66 * The content provider uri to return the list of top level folders for this 67 * account. 68 */ 69 public final Uri folderListUri; 70 /** 71 * The content provider uri to return the list of all folders for this 72 * account. 73 */ 74 public Uri fullFolderListUri; 75 /** 76 * The content provider uri that can be queried for search results. 77 */ 78 public final Uri searchUri; 79 80 /** 81 * The custom from addresses for this account or null if there are none. 82 */ 83 public String accountFromAddresses; 84 85 /** 86 * The content provider uri that can be used to expunge message from this 87 * account. NOTE: This might be better to be an update operation on the 88 * messageUri. 89 */ 90 public final Uri expungeMessageUri; 91 92 /** 93 * The content provider uri that can be used to undo the last operation 94 * performed. 95 */ 96 public final Uri undoUri; 97 98 /** 99 * Uri for EDIT intent that will cause the settings screens for this account type to be 100 * shown. 101 */ 102 public final Uri settingsIntentUri; 103 104 /** 105 * Uri for VIEW intent that will cause the help screens for this account type to be 106 * shown. 107 */ 108 public final Uri helpIntentUri; 109 110 /** 111 * Uri for VIEW intent that will cause the send feedback screens for this account type to be 112 * shown. 113 */ 114 public final Uri sendFeedbackIntentUri; 115 116 /** 117 * Uri for VIEW intent that will cause the reauthentication screen for this account to be 118 * shown. 119 */ 120 public final Uri reauthenticationIntentUri; 121 122 /** 123 * The sync status of the account 124 */ 125 public final int syncStatus; 126 127 /** 128 * Uri for VIEW intent that will cause the compose screen for this account type to be 129 * shown. 130 */ 131 public final Uri composeIntentUri; 132 133 public final String mimeType; 134 /** 135 * URI for recent folders for this account. 136 */ 137 public final Uri recentFolderListUri; 138 /** 139 * The color used for this account in combined view (Email) 140 */ 141 public final int color; 142 /** 143 * URI for default recent folders for this account, if any. 144 */ 145 public final Uri defaultRecentFolderListUri; 146 /** 147 * Settings object for this account. 148 */ 149 public final Settings settings; 150 151 /** 152 * URI for forcing a manual sync of this account. 153 */ 154 public final Uri manualSyncUri; 155 156 /** 157 * URI for account type specific supplementary account info on outgoing links, if any. 158 */ 159 public final Uri viewIntentProxyUri; 160 161 /** 162 * URI for querying for the account cookies to be used when displaying inline content in a 163 * conversation 164 */ 165 public final Uri accoutCookieQueryUri; 166 167 /** 168 * URI to be used with an update() ContentResolver call with a {@link ContentValues} object 169 * where the keys are from the {@link AccountColumns.SettingsColumns}, and the values are the 170 * new values. 171 */ 172 public final Uri updateSettingsUri; 173 174 /** 175 * Transient cache of parsed {@link #accountFromAddresses}, plus an entry for the main account 176 * address. 177 */ 178 private transient List<ReplyFromAccount> mReplyFroms; 179 180 private static final String LOG_TAG = LogTag.getLogTag(); 181 182 /** 183 * Return a serialized String for this account. 184 */ 185 public synchronized String serialize() { 186 JSONObject json = new JSONObject(); 187 try { 188 json.put(UIProvider.AccountColumns.NAME, name); 189 json.put(UIProvider.AccountColumns.TYPE, type); 190 json.put(UIProvider.AccountColumns.PROVIDER_VERSION, providerVersion); 191 json.put(UIProvider.AccountColumns.URI, uri); 192 json.put(UIProvider.AccountColumns.CAPABILITIES, capabilities); 193 json.put(UIProvider.AccountColumns.FOLDER_LIST_URI, folderListUri); 194 json.put(UIProvider.AccountColumns.FULL_FOLDER_LIST_URI, fullFolderListUri); 195 json.put(UIProvider.AccountColumns.SEARCH_URI, searchUri); 196 json.put(UIProvider.AccountColumns.ACCOUNT_FROM_ADDRESSES, accountFromAddresses); 197 json.put(UIProvider.AccountColumns.EXPUNGE_MESSAGE_URI, expungeMessageUri); 198 json.put(UIProvider.AccountColumns.UNDO_URI, undoUri); 199 json.put(UIProvider.AccountColumns.SETTINGS_INTENT_URI, settingsIntentUri); 200 json.put(UIProvider.AccountColumns.HELP_INTENT_URI, helpIntentUri); 201 json.put(UIProvider.AccountColumns.SEND_FEEDBACK_INTENT_URI, sendFeedbackIntentUri); 202 json.put(UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI, 203 reauthenticationIntentUri); 204 json.put(UIProvider.AccountColumns.SYNC_STATUS, syncStatus); 205 json.put(UIProvider.AccountColumns.COMPOSE_URI, composeIntentUri); 206 json.put(UIProvider.AccountColumns.MIME_TYPE, mimeType); 207 json.put(UIProvider.AccountColumns.RECENT_FOLDER_LIST_URI, recentFolderListUri); 208 json.put(UIProvider.AccountColumns.COLOR, color); 209 json.put(UIProvider.AccountColumns.DEFAULT_RECENT_FOLDER_LIST_URI, 210 defaultRecentFolderListUri); 211 json.put(UIProvider.AccountColumns.MANUAL_SYNC_URI, 212 manualSyncUri); 213 json.put(UIProvider.AccountColumns.VIEW_INTENT_PROXY_URI, 214 viewIntentProxyUri); 215 json.put(UIProvider.AccountColumns.ACCOUNT_COOKIE_QUERY_URI, accoutCookieQueryUri); 216 json.put(UIProvider.AccountColumns.UPDATE_SETTINGS_URI, updateSettingsUri); 217 if (settings != null) { 218 json.put(SETTINGS_KEY, settings.toJSON()); 219 } 220 } catch (JSONException e) { 221 LogUtils.wtf(LOG_TAG, e, "Could not serialize account with name %s", name); 222 } 223 return json.toString(); 224 } 225 226 /** 227 * Create a new instance of an Account object using a serialized instance created previously 228 * using {@link #serialize()}. This returns null if the serialized instance was invalid or does 229 * not represent a valid account object. 230 * 231 * @param serializedAccount 232 * @return 233 */ 234 public static Account newinstance(String serializedAccount) { 235 // The heavy lifting is done by Account(name, type, serializedAccount). This method 236 // is a wrapper to check for errors and exceptions and return back a null in cases 237 // something breaks. 238 JSONObject json = null; 239 try { 240 json = new JSONObject(serializedAccount); 241 final String name = (String) json.get(UIProvider.AccountColumns.NAME); 242 final String type = (String) json.get(UIProvider.AccountColumns.TYPE); 243 return new Account(name, type, serializedAccount); 244 } catch (JSONException e) { 245 LogUtils.w(LOG_TAG, e, "Could not create an account from this input: \"%s\"", 246 serializedAccount); 247 return null; 248 } 249 } 250 251 /** 252 * Construct a new Account instance from a previously serialized string. This calls 253 * {@link android.accounts.Account#Account(String, String)} with name and type given as the 254 * first two arguments. 255 * 256 * <p> 257 * This is private. Public uses should go through the safe {@link #newinstance(String)} method. 258 * </p> 259 * @param name name of account in {@link android.accounts.Account} 260 * @param type type of account in {@link android.accounts.Account} 261 * @param jsonAccount string obtained from {@link #serialize()} on a valid account. 262 * @throws JSONException 263 */ 264 private Account(String name, String type, String jsonAccount) throws JSONException { 265 super(name, type); 266 final JSONObject json = new JSONObject(jsonAccount); 267 providerVersion = json.getInt(UIProvider.AccountColumns.PROVIDER_VERSION); 268 uri = Uri.parse(json.optString(UIProvider.AccountColumns.URI)); 269 capabilities = json.getInt(UIProvider.AccountColumns.CAPABILITIES); 270 folderListUri = Utils 271 .getValidUri(json.optString(UIProvider.AccountColumns.FOLDER_LIST_URI)); 272 fullFolderListUri = Utils.getValidUri(json 273 .optString(UIProvider.AccountColumns.FULL_FOLDER_LIST_URI)); 274 searchUri = Utils.getValidUri(json.optString(UIProvider.AccountColumns.SEARCH_URI)); 275 accountFromAddresses = json.optString(UIProvider.AccountColumns.ACCOUNT_FROM_ADDRESSES, 276 ""); 277 expungeMessageUri = Utils.getValidUri(json 278 .optString(UIProvider.AccountColumns.EXPUNGE_MESSAGE_URI)); 279 undoUri = Utils.getValidUri(json.optString(UIProvider.AccountColumns.UNDO_URI)); 280 settingsIntentUri = Utils.getValidUri(json 281 .optString(UIProvider.AccountColumns.SETTINGS_INTENT_URI)); 282 helpIntentUri = Utils 283 .getValidUri(json.optString(UIProvider.AccountColumns.HELP_INTENT_URI)); 284 sendFeedbackIntentUri = Utils.getValidUri(json 285 .optString(UIProvider.AccountColumns.SEND_FEEDBACK_INTENT_URI)); 286 reauthenticationIntentUri = Utils.getValidUri( 287 json.optString(UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI)); 288 syncStatus = json.optInt(UIProvider.AccountColumns.SYNC_STATUS); 289 composeIntentUri = Utils.getValidUri(json.optString(UIProvider.AccountColumns.COMPOSE_URI)); 290 mimeType = json.optString(UIProvider.AccountColumns.MIME_TYPE); 291 recentFolderListUri = Utils.getValidUri(json 292 .optString(UIProvider.AccountColumns.RECENT_FOLDER_LIST_URI)); 293 color = json.optInt(UIProvider.AccountColumns.COLOR, 0); 294 defaultRecentFolderListUri = Utils.getValidUri(json 295 .optString(UIProvider.AccountColumns.DEFAULT_RECENT_FOLDER_LIST_URI)); 296 manualSyncUri = Utils 297 .getValidUri(json.optString(UIProvider.AccountColumns.MANUAL_SYNC_URI)); 298 viewIntentProxyUri = Utils 299 .getValidUri(json.optString(UIProvider.AccountColumns.VIEW_INTENT_PROXY_URI)); 300 accoutCookieQueryUri = Utils.getValidUri( 301 json.optString(UIProvider.AccountColumns.ACCOUNT_COOKIE_QUERY_URI)); 302 updateSettingsUri = Utils.getValidUri( 303 json.optString(UIProvider.AccountColumns.UPDATE_SETTINGS_URI)); 304 305 final Settings jsonSettings = Settings.newInstance(json.optJSONObject(SETTINGS_KEY)); 306 if (jsonSettings != null) { 307 settings = jsonSettings; 308 } else { 309 LogUtils.e(LOG_TAG, new Throwable(), 310 "Unexpected null settings in Account(name, type, jsonAccount)"); 311 settings = Settings.EMPTY_SETTINGS; 312 } 313 } 314 315 public Account(Parcel in) { 316 super(in); 317 providerVersion = in.readInt(); 318 uri = in.readParcelable(null); 319 capabilities = in.readInt(); 320 folderListUri = in.readParcelable(null); 321 fullFolderListUri = in.readParcelable(null); 322 searchUri = in.readParcelable(null); 323 accountFromAddresses = in.readString(); 324 expungeMessageUri = in.readParcelable(null); 325 undoUri = in.readParcelable(null); 326 settingsIntentUri = in.readParcelable(null); 327 helpIntentUri = in.readParcelable(null); 328 sendFeedbackIntentUri = in.readParcelable(null); 329 reauthenticationIntentUri = in.readParcelable(null); 330 syncStatus = in.readInt(); 331 composeIntentUri = in.readParcelable(null); 332 mimeType = in.readString(); 333 recentFolderListUri = in.readParcelable(null); 334 color = in.readInt(); 335 defaultRecentFolderListUri = in.readParcelable(null); 336 manualSyncUri = in.readParcelable(null); 337 viewIntentProxyUri = in.readParcelable(null); 338 accoutCookieQueryUri = in.readParcelable(null); 339 updateSettingsUri = in.readParcelable(null); 340 final String serializedSettings = in.readString(); 341 final Settings parcelSettings = Settings.newInstance(serializedSettings); 342 if (parcelSettings != null) { 343 settings = parcelSettings; 344 } else { 345 LogUtils.e(LOG_TAG, new Throwable(), "Unexpected null settings in Account(Parcel)"); 346 settings = Settings.EMPTY_SETTINGS; 347 } 348 } 349 350 public Account(Cursor cursor) { 351 super(cursor.getString(cursor.getColumnIndex(UIProvider.AccountColumns.NAME)), "unknown"); 352 accountFromAddresses = cursor.getString( 353 cursor.getColumnIndex(UIProvider.AccountColumns.ACCOUNT_FROM_ADDRESSES)); 354 355 final int capabilitiesColumnIndex = 356 cursor.getColumnIndex(UIProvider.AccountColumns.CAPABILITIES); 357 if (capabilitiesColumnIndex != -1) { 358 capabilities = cursor.getInt(capabilitiesColumnIndex); 359 } else { 360 capabilities = 0; 361 } 362 363 providerVersion = 364 cursor.getInt(cursor.getColumnIndex(UIProvider.AccountColumns.PROVIDER_VERSION)); 365 uri = Uri.parse(cursor.getString(cursor.getColumnIndex(UIProvider.AccountColumns.URI))); 366 folderListUri = Uri.parse( 367 cursor.getString(cursor.getColumnIndex(UIProvider.AccountColumns.FOLDER_LIST_URI))); 368 fullFolderListUri = Utils.getValidUri(cursor.getString( 369 cursor.getColumnIndex(UIProvider.AccountColumns.FULL_FOLDER_LIST_URI))); 370 searchUri = Utils.getValidUri( 371 cursor.getString(cursor.getColumnIndex(UIProvider.AccountColumns.SEARCH_URI))); 372 expungeMessageUri = Utils.getValidUri(cursor.getString( 373 cursor.getColumnIndex(UIProvider.AccountColumns.EXPUNGE_MESSAGE_URI))); 374 undoUri = Utils.getValidUri( 375 cursor.getString(cursor.getColumnIndex(UIProvider.AccountColumns.UNDO_URI))); 376 settingsIntentUri = Utils.getValidUri(cursor.getString( 377 cursor.getColumnIndex(UIProvider.AccountColumns.SETTINGS_INTENT_URI))); 378 helpIntentUri = Utils.getValidUri( 379 cursor.getString(cursor.getColumnIndex(UIProvider.AccountColumns.HELP_INTENT_URI))); 380 sendFeedbackIntentUri = Utils.getValidUri(cursor.getString( 381 cursor.getColumnIndex(UIProvider.AccountColumns.SEND_FEEDBACK_INTENT_URI))); 382 reauthenticationIntentUri = Utils.getValidUri(cursor.getString( 383 cursor.getColumnIndex(UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI))); 384 syncStatus = cursor.getInt(cursor.getColumnIndex(UIProvider.AccountColumns.SYNC_STATUS)); 385 composeIntentUri = Utils.getValidUri( 386 cursor.getString(cursor.getColumnIndex(UIProvider.AccountColumns.COMPOSE_URI))); 387 mimeType = cursor.getString(cursor.getColumnIndex(UIProvider.AccountColumns.MIME_TYPE)); 388 recentFolderListUri = Utils.getValidUri(cursor.getString( 389 cursor.getColumnIndex(UIProvider.AccountColumns.RECENT_FOLDER_LIST_URI))); 390 color = cursor.getInt(cursor.getColumnIndex(UIProvider.AccountColumns.COLOR)); 391 defaultRecentFolderListUri = Utils.getValidUri(cursor.getString( 392 cursor.getColumnIndex(UIProvider.AccountColumns.DEFAULT_RECENT_FOLDER_LIST_URI))); 393 manualSyncUri = Utils.getValidUri( 394 cursor.getString(cursor.getColumnIndex(UIProvider.AccountColumns.MANUAL_SYNC_URI))); 395 viewIntentProxyUri = Utils.getValidUri(cursor.getString( 396 cursor.getColumnIndex(UIProvider.AccountColumns.VIEW_INTENT_PROXY_URI))); 397 accoutCookieQueryUri = Utils.getValidUri(cursor.getString( 398 cursor.getColumnIndex(UIProvider.AccountColumns.ACCOUNT_COOKIE_QUERY_URI))); 399 updateSettingsUri = Utils.getValidUri(cursor.getString( 400 cursor.getColumnIndex(UIProvider.AccountColumns.UPDATE_SETTINGS_URI))); 401 settings = new Settings(cursor); 402 } 403 404 /** 405 * Returns an array of all Accounts located at this cursor. This method returns a zero length 406 * array if no account was found. This method does not close the cursor. 407 * @param cursor cursor pointing to the list of accounts 408 * @return the array of all accounts stored at this cursor. 409 */ 410 public static Account[] getAllAccounts(ObjectCursor<Account> cursor) { 411 final int initialLength = cursor.getCount(); 412 if (initialLength <= 0 || !cursor.moveToFirst()) { 413 // Return zero length account array rather than null 414 return new Account[0]; 415 } 416 417 final Account[] allAccounts = new Account[initialLength]; 418 int i = 0; 419 do { 420 allAccounts[i++] = cursor.getModel(); 421 } while (cursor.moveToNext()); 422 // Ensure that the length of the array is accurate 423 assert (i == initialLength); 424 return allAccounts; 425 } 426 427 public boolean supportsCapability(int capability) { 428 return (capabilities & capability) != 0; 429 } 430 431 public boolean isAccountSyncRequired() { 432 return (syncStatus & SyncStatus.INITIAL_SYNC_NEEDED) == SyncStatus.INITIAL_SYNC_NEEDED; 433 } 434 435 public boolean isAccountInitializationRequired() { 436 return (syncStatus & SyncStatus.ACCOUNT_INITIALIZATION_REQUIRED) == 437 SyncStatus.ACCOUNT_INITIALIZATION_REQUIRED; 438 } 439 440 /** 441 * Returns true when when the UI provider has indicated that the account has been initialized, 442 * and sync is not required. 443 */ 444 public boolean isAccountReady() { 445 return !isAccountInitializationRequired() && !isAccountSyncRequired(); 446 } 447 448 @Override 449 public void writeToParcel(Parcel dest, int flags) { 450 super.writeToParcel(dest, flags); 451 dest.writeInt(providerVersion); 452 dest.writeParcelable(uri, 0); 453 dest.writeInt(capabilities); 454 dest.writeParcelable(folderListUri, 0); 455 dest.writeParcelable(fullFolderListUri, 0); 456 dest.writeParcelable(searchUri, 0); 457 dest.writeString(accountFromAddresses); 458 dest.writeParcelable(expungeMessageUri, 0); 459 dest.writeParcelable(undoUri, 0); 460 dest.writeParcelable(settingsIntentUri, 0); 461 dest.writeParcelable(helpIntentUri, 0); 462 dest.writeParcelable(sendFeedbackIntentUri, 0); 463 dest.writeParcelable(reauthenticationIntentUri, 0); 464 dest.writeInt(syncStatus); 465 dest.writeParcelable(composeIntentUri, 0); 466 dest.writeString(mimeType); 467 dest.writeParcelable(recentFolderListUri, 0); 468 dest.writeInt(color); 469 dest.writeParcelable(defaultRecentFolderListUri, 0); 470 dest.writeParcelable(manualSyncUri, 0); 471 dest.writeParcelable(viewIntentProxyUri, 0); 472 dest.writeParcelable(accoutCookieQueryUri, 0); 473 dest.writeParcelable(updateSettingsUri, 0); 474 if (settings == null) { 475 LogUtils.e(LOG_TAG, "unexpected null settings object in writeToParcel"); 476 } 477 dest.writeString(settings != null ? settings.serialize() : ""); 478 } 479 480 @Override 481 public String toString() { 482 final StringBuilder sb = new StringBuilder(); 483 484 sb.append("name="); 485 sb.append(name); 486 sb.append(",type="); 487 sb.append(type); 488 sb.append(",accountFromAddressUri="); 489 sb.append(accountFromAddresses); 490 sb.append(",capabilities="); 491 sb.append(capabilities); 492 sb.append(",providerVersion="); 493 sb.append(providerVersion); 494 sb.append(",folderListUri="); 495 sb.append(folderListUri); 496 sb.append(",fullFolderListUri="); 497 sb.append(fullFolderListUri); 498 sb.append(",searchUri="); 499 sb.append(searchUri); 500 sb.append(",saveDraftUri="); 501 sb.append(",expungeMessageUri="); 502 sb.append(expungeMessageUri); 503 sb.append(",undoUri="); 504 sb.append(undoUri); 505 sb.append(",settingsIntentUri="); 506 sb.append(settingsIntentUri); 507 sb.append(",helpIntentUri="); 508 sb.append(helpIntentUri); 509 sb.append(",sendFeedbackIntentUri="); 510 sb.append(sendFeedbackIntentUri); 511 sb.append(",reauthenticationIntentUri="); 512 sb.append(reauthenticationIntentUri); 513 sb.append(",syncStatus="); 514 sb.append(syncStatus); 515 sb.append(",composeIntentUri="); 516 sb.append(composeIntentUri); 517 sb.append(",mimeType="); 518 sb.append(mimeType); 519 sb.append(",recentFoldersUri="); 520 sb.append(recentFolderListUri); 521 sb.append(",color="); 522 sb.append(Integer.toHexString(color)); 523 sb.append(",defaultRecentFoldersUri="); 524 sb.append(defaultRecentFolderListUri); 525 sb.append(",settings="); 526 sb.append(settings.serialize()); 527 528 return sb.toString(); 529 } 530 531 @Override 532 public boolean equals(Object o) { 533 if (o == this) { 534 return true; 535 } 536 537 if ((o == null) || (o.getClass() != this.getClass())) { 538 return false; 539 } 540 541 final Account other = (Account) o; 542 return TextUtils.equals(name, other.name) && TextUtils.equals(type, other.type) && 543 capabilities == other.capabilities && providerVersion == other.providerVersion && 544 Objects.equal(uri, other.uri) && 545 Objects.equal(folderListUri, other.folderListUri) && 546 Objects.equal(fullFolderListUri, other.fullFolderListUri) && 547 Objects.equal(searchUri, other.searchUri) && 548 Objects.equal(accountFromAddresses, other.accountFromAddresses) && 549 Objects.equal(expungeMessageUri, other.expungeMessageUri) && 550 Objects.equal(undoUri, other.undoUri) && 551 Objects.equal(settingsIntentUri, other.settingsIntentUri) && 552 Objects.equal(helpIntentUri, other.helpIntentUri) && 553 Objects.equal(sendFeedbackIntentUri, other.sendFeedbackIntentUri) && 554 Objects.equal(reauthenticationIntentUri, other.reauthenticationIntentUri) && 555 (syncStatus == other.syncStatus) && 556 Objects.equal(composeIntentUri, other.composeIntentUri) && 557 TextUtils.equals(mimeType, other.mimeType) && 558 Objects.equal(recentFolderListUri, other.recentFolderListUri) && 559 color == other.color && 560 Objects.equal(defaultRecentFolderListUri, other.defaultRecentFolderListUri) && 561 Objects.equal(viewIntentProxyUri, other.viewIntentProxyUri) && 562 Objects.equal(accoutCookieQueryUri, other.accoutCookieQueryUri) && 563 Objects.equal(updateSettingsUri, other.updateSettingsUri) && 564 Objects.equal(settings, other.settings); 565 } 566 567 /** 568 * Returns true if the two accounts differ in sync or server-side settings. 569 * This is <b>not</b> a replacement for {@link #equals(Object)}. 570 * @param other 571 * @return 572 */ 573 public final boolean settingsDiffer(Account other) { 574 // If the other object doesn't exist, they differ significantly. 575 if (other == null) { 576 return true; 577 } 578 // Check all the server-side settings, the user-side settings and the sync status. 579 return ((this.syncStatus != other.syncStatus) 580 || !Objects.equal(accountFromAddresses, other.accountFromAddresses) 581 || color != other.color 582 || (this.settings.hashCode() != other.settings.hashCode())); 583 } 584 585 @Override 586 public int hashCode() { 587 return super.hashCode() 588 ^ Objects.hashCode(name, type, capabilities, providerVersion, uri, folderListUri, 589 fullFolderListUri, searchUri, accountFromAddresses, expungeMessageUri, 590 undoUri, settingsIntentUri, helpIntentUri, sendFeedbackIntentUri, 591 reauthenticationIntentUri, syncStatus, composeIntentUri, mimeType, 592 recentFolderListUri, color, defaultRecentFolderListUri, viewIntentProxyUri, 593 accoutCookieQueryUri, updateSettingsUri); 594 } 595 596 /** 597 * Returns whether two Accounts match, as determined by their base URIs. 598 * <p>For a deep object comparison, use {@link #equals(Object)}. 599 * 600 */ 601 public boolean matches(Account other) { 602 return other != null && Objects.equal(uri, other.uri); 603 } 604 605 public List<ReplyFromAccount> getReplyFroms() { 606 607 if (mReplyFroms == null) { 608 mReplyFroms = Lists.newArrayList(); 609 610 // skip if sending is unsupported 611 if (supportsCapability(AccountCapabilities.SENDING_UNAVAILABLE)) { 612 return mReplyFroms; 613 } 614 615 // add the main account address 616 mReplyFroms.add(new ReplyFromAccount(this, uri, name, name, name, 617 false /* isDefault */, false /* isCustom */)); 618 619 if (!TextUtils.isEmpty(accountFromAddresses)) { 620 try { 621 JSONArray accounts = new JSONArray(accountFromAddresses); 622 623 for (int i = 0, len = accounts.length(); i < len; i++) { 624 final ReplyFromAccount a = ReplyFromAccount.deserialize(this, 625 accounts.getJSONObject(i)); 626 if (a != null) { 627 mReplyFroms.add(a); 628 } 629 } 630 631 } catch (JSONException e) { 632 LogUtils.e(LOG_TAG, e, "Unable to parse accountFromAddresses. name=%s", name); 633 } 634 } 635 } 636 return mReplyFroms; 637 } 638 639 /** 640 * @param fromAddress a raw email address, e.g. "user@domain.com" 641 * @return if the address belongs to this Account (either as the main address or as a 642 * custom-from) 643 */ 644 public boolean ownsFromAddress(String fromAddress) { 645 for (ReplyFromAccount replyFrom : getReplyFroms()) { 646 if (TextUtils.equals(replyFrom.address, fromAddress)) { 647 return true; 648 } 649 } 650 651 return false; 652 } 653 654 @SuppressWarnings("hiding") 655 public static final Creator<Account> CREATOR = new Creator<Account>() { 656 @Override 657 public Account createFromParcel(Parcel source) { 658 return new Account(source); 659 } 660 661 @Override 662 public Account[] newArray(int size) { 663 return new Account[size]; 664 } 665 }; 666 667 /** 668 * Find the position of the given needle in the given array of accounts. 669 * @param haystack the array of accounts to search 670 * @param needle the URI of account to find 671 * @return a position between 0 and haystack.length-1 if an account is found, -1 if not found. 672 */ 673 public static int findPosition(Account[] haystack, Uri needle) { 674 if (haystack != null && haystack.length > 0 && needle != null) { 675 // Need to go through the list of current accounts, and fix the 676 // position. 677 for (int i = 0, size = haystack.length; i < size; ++i) { 678 if (haystack[i].uri.equals(needle)) { 679 LogUtils.d(LOG_TAG, "findPositionOfAccount: Found needle at position %d", i); 680 return i; 681 } 682 } 683 } 684 return -1; 685 } 686 687 /** 688 * Creates a {@link Map} where the column name is the key and the value is the value, which can 689 * be used for populating a {@link MatrixCursor}. 690 */ 691 public Map<String, Object> getMatrixCursorValueMap() { 692 // ImmutableMap.Builder does not allow null values 693 final Map<String, Object> map = new HashMap<String, Object>(); 694 695 map.put(UIProvider.AccountColumns._ID, 0); 696 map.put(UIProvider.AccountColumns.NAME, name); 697 map.put(UIProvider.AccountColumns.TYPE, type); 698 map.put(UIProvider.AccountColumns.PROVIDER_VERSION, providerVersion); 699 map.put(UIProvider.AccountColumns.URI, uri); 700 map.put(UIProvider.AccountColumns.CAPABILITIES, capabilities); 701 map.put(UIProvider.AccountColumns.FOLDER_LIST_URI, folderListUri); 702 map.put(UIProvider.AccountColumns.FULL_FOLDER_LIST_URI, fullFolderListUri); 703 map.put(UIProvider.AccountColumns.SEARCH_URI, searchUri); 704 map.put(UIProvider.AccountColumns.ACCOUNT_FROM_ADDRESSES, accountFromAddresses); 705 map.put(UIProvider.AccountColumns.EXPUNGE_MESSAGE_URI, expungeMessageUri); 706 map.put(UIProvider.AccountColumns.UNDO_URI, undoUri); 707 map.put(UIProvider.AccountColumns.SETTINGS_INTENT_URI, settingsIntentUri); 708 map.put(UIProvider.AccountColumns.HELP_INTENT_URI, helpIntentUri); 709 map.put(UIProvider.AccountColumns.SEND_FEEDBACK_INTENT_URI, sendFeedbackIntentUri); 710 map.put( 711 UIProvider.AccountColumns.REAUTHENTICATION_INTENT_URI, reauthenticationIntentUri); 712 map.put(UIProvider.AccountColumns.SYNC_STATUS, syncStatus); 713 map.put(UIProvider.AccountColumns.COMPOSE_URI, composeIntentUri); 714 map.put(UIProvider.AccountColumns.MIME_TYPE, mimeType); 715 map.put(UIProvider.AccountColumns.RECENT_FOLDER_LIST_URI, recentFolderListUri); 716 map.put(UIProvider.AccountColumns.DEFAULT_RECENT_FOLDER_LIST_URI, 717 defaultRecentFolderListUri); 718 map.put(UIProvider.AccountColumns.MANUAL_SYNC_URI, manualSyncUri); 719 map.put(UIProvider.AccountColumns.VIEW_INTENT_PROXY_URI, viewIntentProxyUri); 720 map.put(UIProvider.AccountColumns.ACCOUNT_COOKIE_QUERY_URI, accoutCookieQueryUri); 721 map.put(UIProvider.AccountColumns.COLOR, color); 722 map.put(UIProvider.AccountColumns.UPDATE_SETTINGS_URI, updateSettingsUri); 723 map.put(AccountColumns.SettingsColumns.SIGNATURE, settings.signature); 724 map.put(AccountColumns.SettingsColumns.AUTO_ADVANCE, settings.getAutoAdvanceSetting()); 725 map.put(AccountColumns.SettingsColumns.MESSAGE_TEXT_SIZE, settings.messageTextSize); 726 map.put(AccountColumns.SettingsColumns.SNAP_HEADERS, settings.snapHeaders); 727 map.put(AccountColumns.SettingsColumns.REPLY_BEHAVIOR, settings.replyBehavior); 728 map.put( 729 AccountColumns.SettingsColumns.HIDE_CHECKBOXES, settings.hideCheckboxes ? 1 : 0); 730 map.put(AccountColumns.SettingsColumns.CONFIRM_DELETE, settings.confirmDelete ? 1 : 0); 731 map.put( 732 AccountColumns.SettingsColumns.CONFIRM_ARCHIVE, settings.confirmArchive ? 1 : 0); 733 map.put(AccountColumns.SettingsColumns.CONFIRM_SEND, settings.confirmSend ? 1 : 0); 734 map.put(AccountColumns.SettingsColumns.DEFAULT_INBOX, settings.defaultInbox); 735 map.put(AccountColumns.SettingsColumns.DEFAULT_INBOX_NAME, settings.defaultInboxName); 736 map.put(AccountColumns.SettingsColumns.FORCE_REPLY_FROM_DEFAULT, 737 settings.forceReplyFromDefault ? 1 : 0); 738 map.put(AccountColumns.SettingsColumns.MAX_ATTACHMENT_SIZE, settings.maxAttachmentSize); 739 map.put(AccountColumns.SettingsColumns.SWIPE, settings.swipe); 740 map.put(AccountColumns.SettingsColumns.PRIORITY_ARROWS_ENABLED, 741 settings.priorityArrowsEnabled ? 1 : 0); 742 map.put(AccountColumns.SettingsColumns.SETUP_INTENT_URI, settings.setupIntentUri); 743 map.put(AccountColumns.SettingsColumns.CONVERSATION_VIEW_MODE, 744 settings.conversationViewMode); 745 map.put(AccountColumns.SettingsColumns.VEILED_ADDRESS_PATTERN, 746 settings.veiledAddressPattern); 747 748 return map; 749 } 750 751 /** 752 * Public object that knows how to construct Accounts given Cursors. 753 */ 754 public final static CursorCreator<Account> FACTORY = new CursorCreator<Account>() { 755 @Override 756 public Account createFromCursor(Cursor c) { 757 return new Account(c); 758 } 759 760 @Override 761 public String toString() { 762 return "Account CursorCreator"; 763 } 764 }; 765} 766