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