Home | History | Annotate | Download | only in providers
      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 
     17 package com.android.mail.providers;
     18 
     19 import android.database.Cursor;
     20 import android.net.Uri;
     21 import android.os.Parcel;
     22 import android.os.Parcelable;
     23 import android.text.TextUtils;
     24 
     25 import com.android.mail.providers.UIProvider.AccountColumns.SettingsColumns;
     26 import com.android.mail.providers.UIProvider.AutoAdvance;
     27 import com.android.mail.providers.UIProvider.ConversationListIcon;
     28 import com.android.mail.providers.UIProvider.DefaultReplyBehavior;
     29 import com.android.mail.providers.UIProvider.SnapHeaderValue;
     30 import com.android.mail.providers.UIProvider.Swipe;
     31 import com.android.mail.utils.LogTag;
     32 import com.android.mail.utils.LogUtils;
     33 import com.android.mail.utils.Utils;
     34 import com.google.android.mail.common.base.Strings;
     35 import com.google.common.base.Objects;
     36 
     37 import org.json.JSONException;
     38 import org.json.JSONObject;
     39 
     40 import java.util.HashMap;
     41 import java.util.Map;
     42 
     43 /**
     44  * Model to hold Settings for an account.
     45  */
     46 public class Settings implements Parcelable {
     47     private static final String LOG_TAG = LogTag.getLogTag();
     48 
     49     static final Settings EMPTY_SETTINGS = new Settings();
     50 
     51     // Max size for attachments (5 megs). Will be overridden by an account
     52     // setting, if found.
     53     private static final int DEFAULT_MAX_ATTACHMENT_SIZE = 5 * 1024 * 1024;
     54 
     55     public static final int SWIPE_SETTING_ARCHIVE = 0;
     56     public static final int SWIPE_SETTING_DELETE = 1;
     57     public static final int SWIPE_SETTING_DISABLED = 2;
     58 
     59     private static final int DEFAULT = SWIPE_SETTING_ARCHIVE;
     60 
     61     public interface ShowImages {
     62         public static final int ALWAYS = 0;
     63         public static final int ASK_FIRST = 1;
     64     }
     65 
     66     public final String signature;
     67     /**
     68      * Auto advance setting for this account.
     69      * Integer, one of {@link AutoAdvance#LIST}, {@link AutoAdvance#NEWER},
     70      * {@link AutoAdvance#OLDER} or  {@link AutoAdvance#UNSET}
     71      */
     72     private final int mAutoAdvance;
     73     private Integer mTransientAutoAdvance = null;
     74     public final int snapHeaders;
     75     public final int replyBehavior;
     76     public final int convListIcon;
     77     public final boolean confirmDelete;
     78     public final boolean confirmArchive;
     79     public final boolean confirmSend;
     80     public final int conversationViewMode;
     81     public final Uri defaultInbox;
     82     /**
     83      * The name of the default inbox: "Inbox" or "Priority Inbox", internationalized...
     84      */
     85     public final String defaultInboxName;
     86     // If you find the need for more default Inbox information: ID or capabilities, then
     87     // ask viki to replace the above two members with a single JSON object representing the default
     88     // folder.  That should make all the information about the folder available without an
     89     // explosion in the number of members.
     90 
     91     public final boolean forceReplyFromDefault;
     92     public final int maxAttachmentSize;
     93     public final int swipe;
     94     /** True if the yellow label indicating importance should be shown. */
     95     public final boolean importanceMarkersEnabled;
     96     /**
     97      * true if personal level indicators should be shown:
     98      * an arrow (  ) by messages sent to my address (not a mailing list),
     99      * and a double arrow (  ) by messages sent only to me.
    100      */
    101     public final boolean showChevronsEnabled;
    102     public final Uri setupIntentUri;
    103     public final String veiledAddressPattern;
    104     public final int showImages;
    105     public final int welcomeTourShownVersion;
    106 
    107     /**
    108      * The {@link Uri} to use when moving a conversation to the inbox. May
    109      * differ from {@link #defaultInbox}.
    110      */
    111     public final Uri moveToInbox;
    112 
    113     /** Cached value of hashCode */
    114     private int mHashCode;
    115 
    116     /** Safe defaults to be used if some values are unspecified. */
    117     private static final Settings sDefault = EMPTY_SETTINGS;
    118 
    119     private Settings() {
    120         signature = "";
    121         mAutoAdvance = AutoAdvance.LIST;
    122         snapHeaders = SnapHeaderValue.ALWAYS;
    123         replyBehavior = DefaultReplyBehavior.REPLY;
    124         convListIcon = ConversationListIcon.SENDER_IMAGE;
    125         confirmDelete = false;
    126         confirmArchive = false;
    127         confirmSend = false;
    128         defaultInbox = Uri.EMPTY;
    129         defaultInboxName = "";
    130         forceReplyFromDefault = false;
    131         maxAttachmentSize = 0;
    132         swipe = DEFAULT;
    133         importanceMarkersEnabled = false;
    134         showChevronsEnabled = false;
    135         setupIntentUri = Uri.EMPTY;
    136         conversationViewMode = UIProvider.ConversationViewMode.UNDEFINED;
    137         veiledAddressPattern = null;
    138         moveToInbox = Uri.EMPTY;
    139         showImages = ShowImages.ASK_FIRST;
    140         welcomeTourShownVersion = -1;
    141     }
    142 
    143     public Settings(Parcel inParcel) {
    144         signature = inParcel.readString();
    145         mAutoAdvance = inParcel.readInt();
    146         snapHeaders = inParcel.readInt();
    147         replyBehavior = inParcel.readInt();
    148         convListIcon = inParcel.readInt();
    149         confirmDelete = inParcel.readInt() != 0;
    150         confirmArchive = inParcel.readInt() != 0;
    151         confirmSend = inParcel.readInt() != 0;
    152         defaultInbox = Utils.getValidUri(inParcel.readString());
    153         defaultInboxName = inParcel.readString();
    154         forceReplyFromDefault = inParcel.readInt() != 0;
    155         maxAttachmentSize = inParcel.readInt();
    156         swipe = inParcel.readInt();
    157         importanceMarkersEnabled = inParcel.readInt() != 0;
    158         showChevronsEnabled = inParcel.readInt() != 0;
    159         setupIntentUri = Utils.getValidUri(inParcel.readString());
    160         conversationViewMode = inParcel.readInt();
    161         veiledAddressPattern = inParcel.readString();
    162         moveToInbox = Utils.getValidUri(inParcel.readString());
    163         showImages = inParcel.readInt();
    164         welcomeTourShownVersion = inParcel.readInt();
    165     }
    166 
    167     public Settings(Cursor cursor) {
    168         signature = Strings.nullToEmpty(
    169                 cursor.getString(cursor.getColumnIndex(SettingsColumns.SIGNATURE)));
    170         mAutoAdvance = cursor.getInt(cursor.getColumnIndex(SettingsColumns.AUTO_ADVANCE));
    171         snapHeaders = cursor.getInt(cursor.getColumnIndex(SettingsColumns.SNAP_HEADERS));
    172         replyBehavior = cursor.getInt(cursor.getColumnIndex(SettingsColumns.REPLY_BEHAVIOR));
    173         convListIcon = cursor.getInt(cursor.getColumnIndex(SettingsColumns.CONV_LIST_ICON));
    174         confirmDelete = cursor.getInt(cursor.getColumnIndex(SettingsColumns.CONFIRM_DELETE)) != 0;
    175         confirmArchive = cursor.getInt(cursor.getColumnIndex(SettingsColumns.CONFIRM_ARCHIVE)) != 0;
    176         confirmSend = cursor.getInt(cursor.getColumnIndex(SettingsColumns.CONFIRM_SEND)) != 0;
    177         defaultInbox = Utils.getValidUri(
    178                 cursor.getString(cursor.getColumnIndex(SettingsColumns.DEFAULT_INBOX)));
    179         defaultInboxName = Strings.nullToEmpty(
    180                 cursor.getString(cursor.getColumnIndex(SettingsColumns.DEFAULT_INBOX_NAME)));
    181         forceReplyFromDefault = cursor.getInt(
    182                 cursor.getColumnIndex(SettingsColumns.FORCE_REPLY_FROM_DEFAULT)) != 0;
    183         maxAttachmentSize =
    184                 cursor.getInt(cursor.getColumnIndex(SettingsColumns.MAX_ATTACHMENT_SIZE));
    185         swipe = cursor.getInt(cursor.getColumnIndex(SettingsColumns.SWIPE));
    186         importanceMarkersEnabled = cursor.getInt(
    187                 cursor.getColumnIndex(SettingsColumns.IMPORTANCE_MARKERS_ENABLED)) != 0;
    188         showChevronsEnabled = cursor.getInt(
    189                 cursor.getColumnIndex(SettingsColumns.SHOW_CHEVRONS_ENABLED)) != 0;
    190         setupIntentUri = Utils.getValidUri(
    191                 cursor.getString(cursor.getColumnIndex(SettingsColumns.SETUP_INTENT_URI)));
    192         conversationViewMode =
    193                 cursor.getInt(cursor.getColumnIndex(SettingsColumns.CONVERSATION_VIEW_MODE));
    194         veiledAddressPattern = Strings.nullToEmpty(
    195                 cursor.getString(cursor.getColumnIndex(SettingsColumns.VEILED_ADDRESS_PATTERN)));
    196         moveToInbox = Utils.getValidUri(
    197                 cursor.getString(cursor.getColumnIndex(SettingsColumns.MOVE_TO_INBOX)));
    198         showImages = cursor.getInt(cursor.getColumnIndex(SettingsColumns.SHOW_IMAGES));
    199         welcomeTourShownVersion = cursor.getInt(
    200                 cursor.getColumnIndex(SettingsColumns.WELCOME_TOUR_SHOWN_VERSION));
    201     }
    202 
    203     private Settings(JSONObject json) {
    204         signature = json.optString(SettingsColumns.SIGNATURE, sDefault.signature);
    205         mAutoAdvance = json.optInt(SettingsColumns.AUTO_ADVANCE, sDefault.getAutoAdvanceSetting());
    206         snapHeaders = json.optInt(SettingsColumns.SNAP_HEADERS, sDefault.snapHeaders);
    207         replyBehavior = json.optInt(SettingsColumns.REPLY_BEHAVIOR, sDefault.replyBehavior);
    208         convListIcon = json.optInt(SettingsColumns.CONV_LIST_ICON, sDefault.convListIcon);
    209         confirmDelete = json.optBoolean(SettingsColumns.CONFIRM_DELETE, sDefault.confirmDelete);
    210         confirmArchive = json.optBoolean(SettingsColumns.CONFIRM_ARCHIVE, sDefault.confirmArchive);
    211         confirmSend = json.optBoolean(SettingsColumns.CONFIRM_SEND, sDefault.confirmSend);
    212         defaultInbox = Utils.getValidUri(json.optString(SettingsColumns.DEFAULT_INBOX));
    213         defaultInboxName = json.optString(SettingsColumns.DEFAULT_INBOX_NAME,
    214                 sDefault.defaultInboxName);
    215         forceReplyFromDefault = json.optBoolean(SettingsColumns.FORCE_REPLY_FROM_DEFAULT,
    216                 sDefault.forceReplyFromDefault);
    217         maxAttachmentSize =
    218                 json.optInt(SettingsColumns.MAX_ATTACHMENT_SIZE, sDefault.maxAttachmentSize);
    219         swipe = json.optInt(SettingsColumns.SWIPE, sDefault.swipe);
    220         importanceMarkersEnabled = json.optBoolean(SettingsColumns.IMPORTANCE_MARKERS_ENABLED,
    221                 sDefault.importanceMarkersEnabled);
    222         showChevronsEnabled = json.optBoolean(SettingsColumns.SHOW_CHEVRONS_ENABLED,
    223                 sDefault.showChevronsEnabled);
    224         setupIntentUri = Utils.getValidUri(json.optString(SettingsColumns.SETUP_INTENT_URI));
    225         conversationViewMode = json.optInt(SettingsColumns.CONVERSATION_VIEW_MODE,
    226                 UIProvider.ConversationViewMode.UNDEFINED);
    227         veiledAddressPattern = json.optString(SettingsColumns.VEILED_ADDRESS_PATTERN, null);
    228         moveToInbox = Utils.getValidUri(json.optString(SettingsColumns.MOVE_TO_INBOX));
    229         showImages = json.optInt(SettingsColumns.SHOW_IMAGES, sDefault.showImages);
    230         welcomeTourShownVersion = json.optInt(
    231                 SettingsColumns.WELCOME_TOUR_SHOWN_VERSION, sDefault.welcomeTourShownVersion);
    232     }
    233 
    234     /**
    235      * Return a serialized String for these settings.
    236      */
    237     public synchronized String serialize() {
    238         final JSONObject json = toJSON();
    239         return json.toString();
    240     }
    241 
    242     private static Object getNonNull(Object candidate, Object fallback){
    243         if (candidate == null)
    244             return fallback;
    245         return candidate;
    246     }
    247 
    248     /**
    249      * Return a JSONObject for these settings.
    250      */
    251     public synchronized JSONObject toJSON() {
    252         final JSONObject json = new JSONObject();
    253         try {
    254             json.put(SettingsColumns.SIGNATURE, getNonNull(signature, sDefault.signature));
    255             json.put(SettingsColumns.AUTO_ADVANCE, getAutoAdvanceSetting());
    256             json.put(SettingsColumns.SNAP_HEADERS, snapHeaders);
    257             json.put(SettingsColumns.REPLY_BEHAVIOR, replyBehavior);
    258             json.put(SettingsColumns.CONV_LIST_ICON, convListIcon);
    259             json.put(SettingsColumns.CONFIRM_DELETE, confirmDelete);
    260             json.put(SettingsColumns.CONFIRM_ARCHIVE, confirmArchive);
    261             json.put(SettingsColumns.CONFIRM_SEND, confirmSend);
    262             json.put(SettingsColumns.DEFAULT_INBOX,
    263                     getNonNull(defaultInbox, sDefault.defaultInbox));
    264             json.put(SettingsColumns.DEFAULT_INBOX_NAME,
    265                     getNonNull(defaultInboxName, sDefault.defaultInboxName));
    266             json.put(SettingsColumns.FORCE_REPLY_FROM_DEFAULT, forceReplyFromDefault);
    267             json.put(SettingsColumns.MAX_ATTACHMENT_SIZE,  maxAttachmentSize);
    268             json.put(SettingsColumns.SWIPE, swipe);
    269             json.put(SettingsColumns.IMPORTANCE_MARKERS_ENABLED, importanceMarkersEnabled);
    270             json.put(SettingsColumns.SHOW_CHEVRONS_ENABLED, showChevronsEnabled);
    271             json.put(SettingsColumns.SETUP_INTENT_URI, setupIntentUri);
    272             json.put(SettingsColumns.CONVERSATION_VIEW_MODE, conversationViewMode);
    273             json.put(SettingsColumns.VEILED_ADDRESS_PATTERN, veiledAddressPattern);
    274             json.put(SettingsColumns.MOVE_TO_INBOX,
    275                     getNonNull(moveToInbox, sDefault.moveToInbox));
    276             json.put(SettingsColumns.SHOW_IMAGES, showImages);
    277             json.put(SettingsColumns.WELCOME_TOUR_SHOWN_VERSION, welcomeTourShownVersion);
    278         } catch (JSONException e) {
    279             LogUtils.wtf(LOG_TAG, e, "Could not serialize settings");
    280         }
    281         return json;
    282     }
    283 
    284     /**
    285      * Creates a {@link Map} where the column name is the key and the value is the value.
    286      * @param map map to insert values into or null
    287      * @return the resulting map
    288      */
    289     public Map<String, Object> getValueMap(Map<String, Object> map) {
    290         if (map == null) {
    291             map = new HashMap<String, Object>();
    292         }
    293 
    294         map.put(SettingsColumns.SIGNATURE, signature);
    295         map.put(SettingsColumns.AUTO_ADVANCE, getAutoAdvanceSetting());
    296         map.put(SettingsColumns.SNAP_HEADERS, snapHeaders);
    297         map.put(SettingsColumns.REPLY_BEHAVIOR, replyBehavior);
    298         map.put(SettingsColumns.CONV_LIST_ICON, convListIcon);
    299         map.put(SettingsColumns.CONFIRM_DELETE, confirmDelete ? 1 : 0);
    300         map.put(SettingsColumns.CONFIRM_ARCHIVE, confirmArchive ? 1 : 0);
    301         map.put(SettingsColumns.CONFIRM_SEND, confirmSend ? 1 : 0);
    302         map.put(SettingsColumns.DEFAULT_INBOX, defaultInbox);
    303         map.put(SettingsColumns.DEFAULT_INBOX_NAME, defaultInboxName);
    304         map.put(SettingsColumns.FORCE_REPLY_FROM_DEFAULT, forceReplyFromDefault ? 1 : 0);
    305         map.put(SettingsColumns.MAX_ATTACHMENT_SIZE, maxAttachmentSize);
    306         map.put(SettingsColumns.SWIPE, swipe);
    307         map.put(SettingsColumns.IMPORTANCE_MARKERS_ENABLED, importanceMarkersEnabled ? 1 : 0);
    308         map.put(SettingsColumns.SHOW_CHEVRONS_ENABLED, showChevronsEnabled ? 1 : 0);
    309         map.put(SettingsColumns.SETUP_INTENT_URI, setupIntentUri);
    310         map.put(SettingsColumns.CONVERSATION_VIEW_MODE, conversationViewMode);
    311         map.put(SettingsColumns.VEILED_ADDRESS_PATTERN, veiledAddressPattern);
    312         map.put(SettingsColumns.MOVE_TO_INBOX, moveToInbox);
    313         map.put(SettingsColumns.SHOW_IMAGES, showImages);
    314         map.put(SettingsColumns.WELCOME_TOUR_SHOWN_VERSION, welcomeTourShownVersion);
    315 
    316         return map;
    317     }
    318 
    319     /**
    320      * Create a new instance of an Settings object using a JSONObject  instance created previously
    321      * using {@link #toJSON()}. This returns null if the serialized instance was invalid or does
    322      * not represent a valid account object.
    323      *
    324      * @param json Serialized object
    325      * @return New settings object or null
    326      */
    327     public static Settings newInstance(JSONObject json) {
    328         if (json == null) {
    329             return null;
    330         }
    331         return new Settings(json);
    332     }
    333 
    334     @Override
    335     public int describeContents() {
    336         return 0;
    337     }
    338 
    339     @Override
    340     public void writeToParcel(Parcel dest, int flags) {
    341         dest.writeString((String) getNonNull(signature, sDefault.signature));
    342         dest.writeInt(getAutoAdvanceSetting());
    343         dest.writeInt(snapHeaders);
    344         dest.writeInt(replyBehavior);
    345         dest.writeInt(convListIcon);
    346         dest.writeInt(confirmDelete ? 1 : 0);
    347         dest.writeInt(confirmArchive? 1 : 0);
    348         dest.writeInt(confirmSend? 1 : 0);
    349         dest.writeString(getNonNull(defaultInbox, sDefault.defaultInbox).toString());
    350         dest.writeString((String) getNonNull(defaultInboxName, sDefault.defaultInboxName));
    351         dest.writeInt(forceReplyFromDefault ? 1 : 0);
    352         dest.writeInt(maxAttachmentSize);
    353         dest.writeInt(swipe);
    354         dest.writeInt(importanceMarkersEnabled ? 1 : 0);
    355         dest.writeInt(showChevronsEnabled ? 1 : 0);
    356         dest.writeString(getNonNull(setupIntentUri, sDefault.setupIntentUri).toString());
    357         dest.writeInt(conversationViewMode);
    358         dest.writeString(veiledAddressPattern);
    359         dest.writeString(getNonNull(moveToInbox, sDefault.moveToInbox).toString());
    360         dest.writeInt(showImages);
    361         dest.writeInt(welcomeTourShownVersion);
    362     }
    363 
    364     /**
    365      * Returns the URI of the current account's default inbox if available, otherwise
    366      * returns the empty URI {@link Uri#EMPTY}
    367      * @param settings a settings object, possibly null.
    368      * @return a valid default Inbox URI, or {@link Uri#EMPTY} if settings are null or no default
    369      * is specified.
    370      */
    371     public static Uri getDefaultInboxUri(Settings settings) {
    372         if (settings == null) {
    373             return sDefault.defaultInbox;
    374         }
    375         return (Uri) getNonNull(settings.defaultInbox, sDefault.defaultInbox);
    376     }
    377 
    378     /**
    379      * Gets the autoadvance setting for this object, which may have changed since the settings were
    380      * initially loaded.
    381      */
    382     public int getAutoAdvanceSetting() {
    383         if (mTransientAutoAdvance != null) {
    384             return mTransientAutoAdvance;
    385         }
    386 
    387         return mAutoAdvance;
    388     }
    389 
    390     /**
    391      * Sets the transient autoadvance setting, which will override the initial autoadvance setting.
    392      */
    393     public void setAutoAdvanceSetting(final int autoAdvance) {
    394         mTransientAutoAdvance = autoAdvance;
    395     }
    396 
    397     /**
    398      * @return true if {@link UIProvider.ConversationViewMode#OVERVIEW} mode is set. In the event
    399      * that the setting is not yet set, fall back to
    400      * {@link UIProvider.ConversationViewMode#DEFAULT}.
    401      */
    402     public boolean isOverviewMode() {
    403         final int val = (conversationViewMode != UIProvider.ConversationViewMode.UNDEFINED) ?
    404                 conversationViewMode : UIProvider.ConversationViewMode.DEFAULT;
    405         return (val == UIProvider.ConversationViewMode.OVERVIEW);
    406     }
    407 
    408     /**
    409      * Return the swipe setting for the settings provided. It is safe to pass this method
    410      * a null object. It always returns a valid {@link Swipe} setting.
    411      * @return the auto advance setting, a constant from {@link Swipe}
    412      */
    413     public static int getSwipeSetting(Settings settings) {
    414         return settings != null ? settings.swipe : sDefault.swipe;
    415     }
    416 
    417     @SuppressWarnings("hiding")
    418     public static final Creator<Settings> CREATOR = new Creator<Settings>() {
    419         @Override
    420         public Settings createFromParcel(Parcel source) {
    421             return new Settings(source);
    422         }
    423 
    424         @Override
    425         public Settings[] newArray(int size) {
    426             return new Settings[size];
    427         }
    428     };
    429 
    430     /**
    431      *  Get the maximum size in bytes for attachments.
    432      */
    433     public int getMaxAttachmentSize() {
    434         return maxAttachmentSize <= 0 ? DEFAULT_MAX_ATTACHMENT_SIZE : maxAttachmentSize;
    435     }
    436 
    437     @Override
    438     public boolean equals(final Object aThat) {
    439         LogUtils.d(LOG_TAG, "Settings.equals(%s)", aThat);
    440         if (this == aThat) {
    441             return true;
    442         }
    443         if ((aThat == null) || (aThat.getClass() != this.getClass())) {
    444             return false;
    445         }
    446         final Settings that = (Settings) aThat;
    447         final boolean autoAdvanceEquals = mTransientAutoAdvance != null
    448                 ? mTransientAutoAdvance.equals(that.mTransientAutoAdvance)
    449                 : that.mTransientAutoAdvance == null;
    450         return (TextUtils.equals(signature, that.signature)
    451                 && mAutoAdvance == that.mAutoAdvance
    452                 && autoAdvanceEquals
    453                 && snapHeaders == that.snapHeaders
    454                 && replyBehavior == that.replyBehavior
    455                 && convListIcon == that.convListIcon
    456                 && confirmDelete == that.confirmDelete
    457                 && confirmArchive == that.confirmArchive
    458                 && confirmSend == that.confirmSend
    459                 && Objects.equal(defaultInbox, that.defaultInbox)
    460                 // Not checking default Inbox name, since is is identical to the URI check above.
    461                 && forceReplyFromDefault == that.forceReplyFromDefault
    462                 && maxAttachmentSize == that.maxAttachmentSize
    463                 && swipe == that.swipe
    464                 && importanceMarkersEnabled == that.importanceMarkersEnabled
    465                 && showChevronsEnabled == that.showChevronsEnabled
    466                 && setupIntentUri == that.setupIntentUri
    467                 && conversationViewMode == that.conversationViewMode
    468                 && TextUtils.equals(veiledAddressPattern, that.veiledAddressPattern))
    469                 && Objects.equal(moveToInbox, that.moveToInbox)
    470                 && welcomeTourShownVersion == that.welcomeTourShownVersion;
    471     }
    472 
    473     @Override
    474     public int hashCode() {
    475         if (mHashCode == 0) {
    476             mHashCode = super.hashCode()
    477                     ^ Objects.hashCode(signature, mAutoAdvance, mTransientAutoAdvance,
    478                     snapHeaders, replyBehavior, convListIcon, confirmDelete, confirmArchive,
    479                     confirmSend, defaultInbox, forceReplyFromDefault, maxAttachmentSize, swipe,
    480                     importanceMarkersEnabled, showChevronsEnabled, setupIntentUri,
    481                     conversationViewMode, veiledAddressPattern, moveToInbox,
    482                     welcomeTourShownVersion);
    483         }
    484         return mHashCode;
    485     }
    486 }
    487