AccountSettingsUtils.java revision 858c2822777f74947e81476125590ad06bfe4803
1/*
2 * Copyright (C) 2009 The Android Open Source Project
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.email.activity.setup;
18
19import com.android.email.AccountBackupRestore;
20import com.android.email.Email;
21import com.android.email.R;
22import com.android.email.VendorPolicyLoader;
23import com.android.email.provider.EmailContent;
24import com.android.email.provider.EmailContent.AccountColumns;
25
26import android.content.ContentValues;
27import android.content.Context;
28import android.content.res.XmlResourceParser;
29import android.text.Editable;
30import android.util.Log;
31import android.widget.EditText;
32
33import java.io.Serializable;
34import java.net.URI;
35
36public class AccountSettingsUtils {
37
38    /**
39     * Commits the UI-related settings of an account to the provider.  This is static so that it
40     * can be used by the various account activities.  If the account has never been saved, this
41     * method saves it; otherwise, it just saves the settings.
42     * @param context the context of the caller
43     * @param account the account whose settings will be committed
44     */
45    public static void commitSettings(Context context, EmailContent.Account account) {
46        if (!account.isSaved()) {
47            account.save(context);
48        } else {
49            ContentValues cv = getAccountContentValues(account);
50            account.update(context, cv);
51        }
52        // Update the backup (side copy) of the accounts
53        AccountBackupRestore.backupAccounts(context);
54    }
55
56    /**
57     * Returns a set of content values to commit account changes (not including HostAuth) to
58     * the database.  Does not actually commit anything.
59     */
60    public static ContentValues getAccountContentValues(EmailContent.Account account) {
61        ContentValues cv = new ContentValues();
62        cv.put(AccountColumns.IS_DEFAULT, account.mIsDefault);
63        cv.put(AccountColumns.DISPLAY_NAME, account.getDisplayName());
64        cv.put(AccountColumns.SENDER_NAME, account.getSenderName());
65        cv.put(AccountColumns.SIGNATURE, account.getSignature());
66        cv.put(AccountColumns.SYNC_INTERVAL, account.mSyncInterval);
67        cv.put(AccountColumns.RINGTONE_URI, account.mRingtoneUri);
68        cv.put(AccountColumns.FLAGS, account.mFlags);
69        cv.put(AccountColumns.SYNC_LOOKBACK, account.mSyncLookback);
70        cv.put(AccountColumns.SECURITY_FLAGS, account.mSecurityFlags);
71        cv.put(AccountColumns.SECURITY_SYNC_KEY, account.mSecuritySyncKey);
72        return cv;
73    }
74
75    /**
76     * Search the list of known Email providers looking for one that matches the user's email
77     * domain.  We check for vendor supplied values first, then we look in providers_product.xml,
78     * and finally by the entries in platform providers.xml.  This provides a nominal override
79     * capability.
80     *
81     * A match is defined as any provider entry for which the "domain" attribute matches.
82     *
83     * @param domain The domain portion of the user's email address
84     * @return suitable Provider definition, or null if no match found
85     */
86    public static Provider findProviderForDomain(Context context, String domain) {
87        Provider p = VendorPolicyLoader.getInstance(context).findProviderForDomain(domain);
88        if (p == null) {
89            p = findProviderForDomain(context, domain, R.xml.providers_product);
90        }
91        if (p == null) {
92            p = findProviderForDomain(context, domain, R.xml.providers);
93        }
94        return p;
95    }
96
97    /**
98     * Search a single resource containing known Email provider definitions.
99     *
100     * @param domain The domain portion of the user's email address
101     * @param resourceId Id of the provider resource to scan
102     * @return suitable Provider definition, or null if no match found
103     */
104    private static Provider findProviderForDomain(Context context, String domain, int resourceId) {
105        try {
106            XmlResourceParser xml = context.getResources().getXml(resourceId);
107            int xmlEventType;
108            Provider provider = null;
109            while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
110                if (xmlEventType == XmlResourceParser.START_TAG
111                        && "provider".equals(xml.getName())
112                        && domain.equalsIgnoreCase(getXmlAttribute(context, xml, "domain"))) {
113                    provider = new Provider();
114                    provider.id = getXmlAttribute(context, xml, "id");
115                    provider.label = getXmlAttribute(context, xml, "label");
116                    provider.domain = getXmlAttribute(context, xml, "domain");
117                    provider.note = getXmlAttribute(context, xml, "note");
118                }
119                else if (xmlEventType == XmlResourceParser.START_TAG
120                        && "incoming".equals(xml.getName())
121                        && provider != null) {
122                    provider.incomingUriTemplate = new URI(getXmlAttribute(context, xml, "uri"));
123                    provider.incomingUsernameTemplate = getXmlAttribute(context, xml, "username");
124                }
125                else if (xmlEventType == XmlResourceParser.START_TAG
126                        && "outgoing".equals(xml.getName())
127                        && provider != null) {
128                    provider.outgoingUriTemplate = new URI(getXmlAttribute(context, xml, "uri"));
129                    provider.outgoingUsernameTemplate = getXmlAttribute(context, xml, "username");
130                }
131                else if (xmlEventType == XmlResourceParser.END_TAG
132                        && "provider".equals(xml.getName())
133                        && provider != null) {
134                    return provider;
135                }
136            }
137        }
138        catch (Exception e) {
139            Log.e(Email.LOG_TAG, "Error while trying to load provider settings.", e);
140        }
141        return null;
142    }
143
144    /**
145     * Attempts to get the given attribute as a String resource first, and if it fails
146     * returns the attribute as a simple String value.
147     * @param xml
148     * @param name
149     * @return the requested resource
150     */
151    private static String getXmlAttribute(Context context, XmlResourceParser xml, String name) {
152        int resId = xml.getAttributeResourceValue(null, name, 0);
153        if (resId == 0) {
154            return xml.getAttributeValue(null, name);
155        }
156        else {
157            return context.getString(resId);
158        }
159    }
160
161    public static class Provider implements Serializable {
162        private static final long serialVersionUID = 8511656164616538989L;
163
164        public String id;
165        public String label;
166        public String domain;
167        public URI incomingUriTemplate;
168        public String incomingUsernameTemplate;
169        public URI outgoingUriTemplate;
170        public String outgoingUsernameTemplate;
171        public String note;
172    }
173
174    /**
175     * Infer potential email server addresses from domain names
176     *
177     * Incoming: Prepend "imap" or "pop3" to domain, unless "pop", "pop3",
178     *          "imap", or "mail" are found.
179     * Outgoing: Prepend "smtp" if "pop", "pop3", "imap" are found.
180     *          Leave "mail" as-is.
181     * TBD: Are there any useful defaults for exchange?
182     *
183     * @param server name as we know it so far
184     * @param incoming "pop3" or "imap" (or null)
185     * @param outgoing "smtp" or null
186     * @return the post-processed name for use in the UI
187     */
188    public static String inferServerName(String server, String incoming, String outgoing) {
189        // Default values cause entire string to be kept, with prepended server string
190        int keepFirstChar = 0;
191        int firstDotIndex = server.indexOf('.');
192        if (firstDotIndex != -1) {
193            // look at first word and decide what to do
194            String firstWord = server.substring(0, firstDotIndex).toLowerCase();
195            boolean isImapOrPop = "imap".equals(firstWord)
196                    || "pop3".equals(firstWord) || "pop".equals(firstWord);
197            boolean isMail = "mail".equals(firstWord);
198            // Now decide what to do
199            if (incoming != null) {
200                // For incoming, we leave imap/pop/pop3/mail alone, or prepend incoming
201                if (isImapOrPop || isMail) {
202                    return server;
203                }
204            } else {
205                // For outgoing, replace imap/pop/pop3 with outgoing, leave mail alone, or
206                // prepend outgoing
207                if (isImapOrPop) {
208                    keepFirstChar = firstDotIndex + 1;
209                } else if (isMail) {
210                    return server;
211                } else {
212                    // prepend
213                }
214            }
215        }
216        return ((incoming != null) ? incoming : outgoing) + '.' + server.substring(keepFirstChar);
217    }
218
219    /**
220     * Helper to set error status on password fields that have leading or trailing spaces
221     */
222    public static void checkPasswordSpaces(Context context, EditText passwordField) {
223        // STOPSHIP - there is a bug in the framework that makes these flicker.
224        // If the bug cannot be fixed shortly, then this should be pulled before we ship
225        Editable password = passwordField.getText();
226        int length = password.length();
227        if (length > 0) {
228            if (password.charAt(0) == ' ' || password.charAt(length-1) == ' ') {
229                passwordField.setError(context.getString(R.string.account_password_spaces_error));
230            }
231        }
232    }
233
234}
235