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