Settings.java revision 57899081749fac79c25362cc591705f8bd1c1f58
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 com.google.common.base.Objects;
20
21import com.android.mail.providers.UIProvider.AccountColumns;
22import com.android.mail.providers.UIProvider.AutoAdvance;
23import com.android.mail.providers.UIProvider.DefaultReplyBehavior;
24import com.android.mail.providers.UIProvider.MessageTextSize;
25import com.android.mail.providers.UIProvider.SnapHeaderValue;
26import com.android.mail.providers.UIProvider.Swipe;
27import com.android.mail.utils.LogTag;
28import com.android.mail.utils.LogUtils;
29import com.android.mail.utils.Utils;
30
31import android.database.Cursor;
32import android.net.Uri;
33import android.os.Parcel;
34import android.os.Parcelable;
35import android.text.TextUtils;
36
37import org.json.JSONException;
38import org.json.JSONObject;
39
40/**
41 * Model to hold Settings for an account.
42 */
43public class Settings implements Parcelable {
44    private static final String LOG_TAG = LogTag.getLogTag();
45
46    static final Settings EMPTY_SETTINGS = new Settings();
47
48    // Max size for attachments (5 megs). Will be overridden by an account
49    // setting, if found.
50    private static final int DEFAULT_MAX_ATTACHMENT_SIZE = 5 * 1024 * 1024;
51
52    public static final int SWIPE_SETTING_ARCHIVE = 0;
53    public static final int SWIPE_SETTING_DELETE = 1;
54    public static final int SWIPE_SETTING_DISABLED = 2;
55
56    private static final int DEFAULT = SWIPE_SETTING_ARCHIVE;
57
58    public final String signature;
59    /**
60     * Auto advance setting for this account.
61     * Integer, one of {@link AutoAdvance#LIST}, {@link AutoAdvance#NEWER},
62     * {@link AutoAdvance#OLDER} or  {@link AutoAdvance#UNSET}
63     */
64    public final int autoAdvance;
65    public final int messageTextSize;
66    public final int snapHeaders;
67    public final int replyBehavior;
68    public final boolean hideCheckboxes;
69    public final boolean confirmDelete;
70    public final boolean confirmArchive;
71    public final boolean confirmSend;
72    public final Uri defaultInbox;
73    /**
74     * The name of the default inbox: "Inbox" or "Priority Inbox", internationalized...
75     */
76    public final String defaultInboxName;
77    // If you find the need for more default Inbox information: ID or capabilities, then
78    // ask viki to replace the above two members with a single JSON object representing the default
79    // folder.  That should make all the information about the folder available without an
80    // explosion in the number of members.
81
82    public final boolean forceReplyFromDefault;
83    public final int maxAttachmentSize;
84    public final int swipe;
85    /** True if arrows on the priority inbox are enabled. */
86    public final boolean priorityArrowsEnabled;
87    public final Uri setupIntentUri;
88
89    /** Cached value of hashCode */
90    private int mHashCode;
91
92    /** Safe defaults to be used if some values are unspecified. */
93    private static final Settings sDefault = EMPTY_SETTINGS;
94
95    private Settings() {
96        signature = "";
97        autoAdvance = AutoAdvance.LIST;
98        messageTextSize = MessageTextSize.NORMAL;
99        snapHeaders = SnapHeaderValue.ALWAYS;
100        replyBehavior = DefaultReplyBehavior.REPLY;
101        hideCheckboxes = false;
102        confirmDelete = false;
103        confirmArchive = false;
104        confirmSend = false;
105        defaultInbox = Uri.EMPTY;
106        defaultInboxName = "";
107        forceReplyFromDefault = false;
108        maxAttachmentSize = 0;
109        swipe = DEFAULT;
110        priorityArrowsEnabled = false;
111        setupIntentUri = Uri.EMPTY;
112    }
113
114    public Settings(Parcel inParcel) {
115        signature = inParcel.readString();
116        autoAdvance = inParcel.readInt();
117        messageTextSize = inParcel.readInt();
118        snapHeaders = inParcel.readInt();
119        replyBehavior = inParcel.readInt();
120        hideCheckboxes = inParcel.readInt() != 0;
121        confirmDelete = inParcel.readInt() != 0;
122        confirmArchive = inParcel.readInt() != 0;
123        confirmSend = inParcel.readInt() != 0;
124        defaultInbox = Utils.getValidUri(inParcel.readString());
125        defaultInboxName = inParcel.readString();
126        forceReplyFromDefault = inParcel.readInt() != 0;
127        maxAttachmentSize = inParcel.readInt();
128        swipe = inParcel.readInt();
129        priorityArrowsEnabled = inParcel.readInt() != 0;
130        setupIntentUri = Utils.getValidUri(inParcel.readString());
131    }
132
133    public Settings(Cursor cursor) {
134        signature = cursor.getString(UIProvider.ACCOUNT_SETTINGS_SIGNATURE_COLUMN);
135        autoAdvance = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_AUTO_ADVANCE_COLUMN);
136        messageTextSize = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_MESSAGE_TEXT_SIZE_COLUMN);
137        snapHeaders = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_SNAP_HEADERS_COLUMN);
138        replyBehavior = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_REPLY_BEHAVIOR_COLUMN);
139        hideCheckboxes = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_HIDE_CHECKBOXES_COLUMN) != 0;
140        confirmDelete = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_CONFIRM_DELETE_COLUMN) != 0;
141        confirmArchive = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_CONFIRM_ARCHIVE_COLUMN) != 0;
142        confirmSend = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_CONFIRM_SEND_COLUMN) != 0;
143        defaultInbox = Utils.getValidUri(
144                cursor.getString(UIProvider.ACCOUNT_SETTINGS_DEFAULT_INBOX_COLUMN));
145        defaultInboxName = cursor.getString(UIProvider.ACCOUNT_SETTINGS_DEFAULT_INBOX_NAME_COLUMN);
146        forceReplyFromDefault = cursor.getInt(
147                UIProvider.ACCOUNT_SETTINGS_FORCE_REPLY_FROM_DEFAULT_COLUMN) != 0;
148        maxAttachmentSize = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_MAX_ATTACHMENT_SIZE_COLUMN);
149        swipe = cursor.getInt(UIProvider.ACCOUNT_SETTINGS_SWIPE_COLUMN);
150        priorityArrowsEnabled =
151                cursor.getInt(UIProvider.ACCOUNT_SETTINGS_PRIORITY_ARROWS_ENABLED_COLUMN) != 0;
152        setupIntentUri = Utils.getValidUri(
153                cursor.getString(UIProvider.ACCOUNT_SETTINGS_SETUP_INTENT_URI));
154    }
155
156    private Settings(JSONObject json) {
157        signature = json.optString(AccountColumns.SettingsColumns.SIGNATURE, sDefault.signature);
158        autoAdvance = json.optInt(AccountColumns.SettingsColumns.AUTO_ADVANCE,
159                sDefault.autoAdvance);
160        messageTextSize = json.optInt(AccountColumns.SettingsColumns.MESSAGE_TEXT_SIZE,
161                sDefault.messageTextSize);
162        snapHeaders = json.optInt(AccountColumns.SettingsColumns.SNAP_HEADERS,
163                sDefault.snapHeaders);
164        replyBehavior = json.optInt(AccountColumns.SettingsColumns.REPLY_BEHAVIOR,
165                sDefault.replyBehavior);
166        hideCheckboxes = json.optBoolean(AccountColumns.SettingsColumns.HIDE_CHECKBOXES,
167                sDefault.hideCheckboxes);
168        confirmDelete = json.optBoolean(AccountColumns.SettingsColumns.CONFIRM_DELETE,
169                sDefault.confirmDelete);
170        confirmArchive = json.optBoolean(AccountColumns.SettingsColumns.CONFIRM_ARCHIVE,
171                sDefault.confirmArchive);
172        confirmSend = json.optBoolean(AccountColumns.SettingsColumns.CONFIRM_SEND,
173                sDefault.confirmSend);
174        defaultInbox = Utils.getValidUri(
175                json.optString(AccountColumns.SettingsColumns.DEFAULT_INBOX));
176        defaultInboxName = json.optString(AccountColumns.SettingsColumns.DEFAULT_INBOX_NAME,
177                sDefault.defaultInboxName);
178        forceReplyFromDefault =
179                json.optBoolean(AccountColumns.SettingsColumns.FORCE_REPLY_FROM_DEFAULT,
180                        sDefault.forceReplyFromDefault);
181        maxAttachmentSize = json.optInt(AccountColumns.SettingsColumns.MAX_ATTACHMENT_SIZE,
182                sDefault.maxAttachmentSize);
183        swipe = json.optInt(AccountColumns.SettingsColumns.SWIPE, sDefault.swipe);
184        priorityArrowsEnabled =
185                json.optBoolean(AccountColumns.SettingsColumns.PRIORITY_ARROWS_ENABLED,
186                        sDefault.priorityArrowsEnabled);
187        setupIntentUri = Utils.getValidUri(
188                json.optString(AccountColumns.SettingsColumns.SETUP_INTENT_URI));
189    }
190
191    /**
192     * Return a serialized String for these settings.
193     */
194    public synchronized String serialize() {
195        final JSONObject json = toJSON();
196        return json.toString();
197    }
198
199    private static final Object getNonNull(Object candidate, Object fallback){
200        if (candidate == null)
201            return fallback;
202        return candidate;
203    }
204
205    /**
206     * Return a JSONObject for these settings.
207     */
208    public synchronized JSONObject toJSON() {
209        final JSONObject json = new JSONObject();
210        try {
211            json.put(AccountColumns.SettingsColumns.SIGNATURE,
212                    getNonNull(signature, sDefault.signature));
213            json.put(AccountColumns.SettingsColumns.AUTO_ADVANCE, autoAdvance);
214            json.put(AccountColumns.SettingsColumns.MESSAGE_TEXT_SIZE, messageTextSize);
215            json.put(AccountColumns.SettingsColumns.SNAP_HEADERS, snapHeaders);
216            json.put(AccountColumns.SettingsColumns.REPLY_BEHAVIOR, replyBehavior);
217            json.put(AccountColumns.SettingsColumns.HIDE_CHECKBOXES, hideCheckboxes);
218            json.put(AccountColumns.SettingsColumns.CONFIRM_DELETE, confirmDelete);
219            json.put(AccountColumns.SettingsColumns.CONFIRM_ARCHIVE, confirmArchive);
220            json.put(AccountColumns.SettingsColumns.CONFIRM_SEND, confirmSend);
221            json.put(AccountColumns.SettingsColumns.DEFAULT_INBOX,
222                    getNonNull(defaultInbox, sDefault.defaultInbox));
223            json.put(AccountColumns.SettingsColumns.DEFAULT_INBOX_NAME,
224                    getNonNull(defaultInboxName, sDefault.defaultInboxName));
225            json.put(AccountColumns.SettingsColumns.FORCE_REPLY_FROM_DEFAULT,
226                    forceReplyFromDefault);
227            json.put(AccountColumns.SettingsColumns.MAX_ATTACHMENT_SIZE,
228                    maxAttachmentSize);
229            json.put(AccountColumns.SettingsColumns.SWIPE, swipe);
230            json.put(AccountColumns.SettingsColumns.PRIORITY_ARROWS_ENABLED, priorityArrowsEnabled);
231            json.put(AccountColumns.SettingsColumns.SETUP_INTENT_URI, setupIntentUri);
232        } catch (JSONException e) {
233            LogUtils.wtf(LOG_TAG, e, "Could not serialize settings");
234        }
235        return json;
236    }
237
238    /**
239     * Create a new instance of an Settings object using a serialized instance created previously
240     * using {@link #serialize()}. This returns null if the serialized instance was invalid or does
241     * not represent a valid account object.
242     *
243     * @param serializedAccount
244     * @return
245     */
246    public static Settings newInstance(String serializedSettings) {
247        JSONObject json = null;
248        try {
249            json = new JSONObject(serializedSettings);
250            return new Settings(json);
251        } catch (JSONException e) {
252            LogUtils.e(LOG_TAG, e, "Could not create an settings from this input: \"%s\"",
253                    serializedSettings);
254            return null;
255        }
256    }
257
258    /**
259     * Create a new instance of an Settings object using a JSONObject  instance created previously
260     * using {@link #toJSON()}. This returns null if the serialized instance was invalid or does
261     * not represent a valid account object.
262     *
263     * @param json
264     * @return
265     */
266    public static Settings newInstance(JSONObject json) {
267        if (json == null) {
268            return null;
269        }
270        return new Settings(json);
271    }
272
273    @Override
274    public int describeContents() {
275        return 0;
276    }
277
278    @Override
279    public void writeToParcel(Parcel dest, int flags) {
280        dest.writeString((String) getNonNull(signature, sDefault.signature));
281        dest.writeInt(autoAdvance);
282        dest.writeInt(messageTextSize);
283        dest.writeInt(snapHeaders);
284        dest.writeInt(replyBehavior);
285        dest.writeInt(hideCheckboxes ? 1 : 0);
286        dest.writeInt(confirmDelete ? 1 : 0);
287        dest.writeInt(confirmArchive? 1 : 0);
288        dest.writeInt(confirmSend? 1 : 0);
289        dest.writeString(((Uri) getNonNull(defaultInbox, sDefault.defaultInbox)).toString());
290        dest.writeString((String) getNonNull(defaultInboxName, sDefault.defaultInboxName));
291        dest.writeInt(forceReplyFromDefault ? 1 : 0);
292        dest.writeInt(maxAttachmentSize);
293        dest.writeInt(swipe);
294        dest.writeInt(priorityArrowsEnabled ? 1 : 0);
295        dest.writeString(((Uri) getNonNull(setupIntentUri, sDefault.setupIntentUri)).toString());
296    }
297
298    /**
299     * Returns the URI of the current account's default inbox if available, otherwise
300     * returns the empty URI {@link Uri#EMPTY}
301     * @param settings a settings object, possibly null.
302     * @return a valid default Inbox URI, or {@link Uri#EMPTY} if settings are null or no default
303     * is specified.
304     */
305    public static Uri getDefaultInboxUri(Settings settings) {
306        if (settings == null) {
307            return sDefault.defaultInbox;
308        }
309        return (Uri) getNonNull(settings.defaultInbox, sDefault.defaultInbox);
310    }
311
312    /**
313     * Return the auto advance setting for the settings provided. It is safe to pass this method
314     * a null object. It always returns a valid {@link AutoAdvance} setting.
315     * @return the auto advance setting, a constant from {@link AutoAdvance}
316     */
317    public static int getAutoAdvanceSetting(Settings settings) {
318        // TODO(mindyp): if this isn't set, then show the dialog telling the user to set it.
319        // Remove defaulting to AutoAdvance.LIST.
320        final int autoAdvance = (settings != null) ?
321                (settings.autoAdvance == AutoAdvance.UNSET ?
322                        AutoAdvance.LIST : settings.autoAdvance)
323                : AutoAdvance.LIST;
324        return autoAdvance;
325    }
326
327    /**
328     * Return the swipe setting for the settings provided. It is safe to pass this method
329     * a null object. It always returns a valid {@link Swipe} setting.
330     * @return the auto advance setting, a constant from {@link Swipe}
331     */
332    public static int getSwipeSetting(Settings settings) {
333        return settings != null ? settings.swipe : sDefault.swipe;
334    }
335
336    @SuppressWarnings("hiding")
337    public static final Creator<Settings> CREATOR = new Creator<Settings>() {
338        @Override
339        public Settings createFromParcel(Parcel source) {
340            return new Settings(source);
341        }
342
343        @Override
344        public Settings[] newArray(int size) {
345            return new Settings[size];
346        }
347    };
348
349    /**
350     *  Get the maximum size in bytes for attachments.
351     */
352    public int getMaxAttachmentSize() {
353        return maxAttachmentSize <= 0 ? DEFAULT_MAX_ATTACHMENT_SIZE : maxAttachmentSize;
354    }
355
356    @Override
357    public boolean equals(final Object aThat) {
358        LogUtils.d(LOG_TAG, "Settings.equals(%s)", aThat);
359        if (this == aThat) {
360            return true;
361        }
362        if ((aThat == null) || (aThat.getClass() != this.getClass())) {
363            return false;
364        }
365        final Settings that = (Settings) aThat;
366        return (TextUtils.equals(signature, that.signature)
367                && autoAdvance == that.autoAdvance
368                && messageTextSize == that.messageTextSize
369                && replyBehavior == that.replyBehavior
370                && hideCheckboxes == that.hideCheckboxes
371                && confirmDelete == that.confirmDelete
372                && confirmArchive == that.confirmArchive
373                && confirmSend == that.confirmSend
374                && Objects.equal(defaultInbox, that.defaultInbox)
375                // Not checking default Inbox name, since is is identical to the URI check above.
376                && forceReplyFromDefault == that.forceReplyFromDefault
377                && maxAttachmentSize == that.maxAttachmentSize
378                && swipe == that.swipe
379                && priorityArrowsEnabled == that.priorityArrowsEnabled
380                && setupIntentUri == that.setupIntentUri);
381    }
382
383    @Override
384    public int hashCode() {
385        if (mHashCode == 0) {
386            mHashCode = calculateHashCode();
387        }
388        return mHashCode;
389    }
390
391    /**
392     * Returns the hash code for this object.
393     * @return
394     */
395    private final int calculateHashCode() {
396        return super.hashCode()
397                ^ Objects.hashCode(signature, autoAdvance, messageTextSize, replyBehavior,
398                        hideCheckboxes, confirmDelete, confirmArchive, confirmSend,
399                        defaultInbox, forceReplyFromDefault, maxAttachmentSize, swipe,
400                        priorityArrowsEnabled, setupIntentUri);
401    }
402}
403