EmailServiceUtils.java revision 54b6b8b072100551c1820d679108bd8356a0c8be
1/*
2 * Copyright (C) 2010 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.service;
18
19import android.app.Service;
20import android.content.Context;
21import android.content.Intent;
22import android.content.res.Resources;
23import android.content.res.TypedArray;
24import android.content.res.XmlResourceParser;
25import android.os.Bundle;
26import android.os.IBinder;
27import android.os.RemoteException;
28import android.util.Log;
29
30import com.android.email.R;
31import com.android.emailcommon.Api;
32import com.android.emailcommon.Logging;
33import com.android.emailcommon.provider.Account;
34import com.android.emailcommon.provider.HostAuth;
35import com.android.emailcommon.service.EmailServiceProxy;
36import com.android.emailcommon.service.IEmailService;
37import com.android.emailcommon.service.IEmailServiceCallback;
38import com.android.emailcommon.service.SearchParams;
39import com.android.emailcommon.service.SyncWindow;
40
41import org.xmlpull.v1.XmlPullParserException;
42
43import java.io.IOException;
44import java.util.ArrayList;
45import java.util.List;
46
47/**
48 * Utility functions for EmailService support.
49 */
50public class EmailServiceUtils {
51    private static final ArrayList<EmailServiceInfo> sServiceList =
52            new ArrayList<EmailServiceInfo>();
53
54    /**
55     * Starts an EmailService by protocol
56     */
57    public static void startService(Context context, String protocol) {
58        EmailServiceInfo info = getServiceInfo(context, protocol);
59        if (info != null && info.intentAction != null) {
60            context.startService(new Intent(info.intentAction));
61        }
62    }
63
64    /**
65     * Starts all remote services
66     */
67    public static void startRemoteServices(Context context) {
68        for (EmailServiceInfo info: getServiceInfoList(context)) {
69            if (info.intentAction != null) {
70                context.startService(new Intent(info.intentAction));
71            }
72        }
73    }
74
75    /**
76     * Returns whether or not remote services are present on device
77     */
78    public static boolean areRemoteServicesInstalled(Context context) {
79        for (EmailServiceInfo info: getServiceInfoList(context)) {
80            if (info.intentAction != null) {
81                return true;
82            }
83        }
84        return false;
85    }
86
87    /**
88     * Starts all remote services
89     */
90    public static void setRemoteServicesLogging(Context context, int debugBits) {
91        for (EmailServiceInfo info: getServiceInfoList(context)) {
92            if (info.intentAction != null) {
93                EmailServiceProxy service =
94                        EmailServiceUtils.getService(context, null, info.protocol);
95                if (service != null) {
96                    try {
97                        service.setLogging(debugBits);
98                    } catch (RemoteException e) {
99                        // Move along, nothing to see
100                    }
101                }
102            }
103        }
104    }
105
106    /**
107     * Determine if the EmailService is available
108     */
109    public static boolean isServiceAvailable(Context context, String protocol) {
110        EmailServiceInfo info = getServiceInfo(context, protocol);
111        if (info == null) return false;
112        if (info.klass != null) return true;
113        return new EmailServiceProxy(context, info.intentAction, null).test();
114    }
115
116    /**
117     * For a given account id, return a service proxy if applicable, or null.
118     *
119     * @param accountId the message of interest
120     * @result service proxy, or null if n/a
121     */
122    public static EmailServiceProxy getServiceForAccount(Context context,
123            IEmailServiceCallback callback, long accountId) {
124        return getService(context, callback, Account.getProtocol(context, accountId));
125    }
126
127    /**
128     * Holder of service information (currently just name and class/intent); if there is a class
129     * member, this is a (local, i.e. same process) service; otherwise, this is a remote service
130     */
131    public static class EmailServiceInfo {
132        public String protocol;
133        public String name;
134        public String accountType;
135        Class<? extends Service> klass;
136        String intentAction;
137        public int port;
138        public int portSsl;
139        public boolean defaultSsl;
140        public boolean offerTls;
141        public boolean offerCerts;
142        public boolean usesSmtp;
143        public boolean offerLocalDeletes;
144        public int defaultLocalDeletes;
145        public boolean offerPrefix;
146        public boolean usesAutodiscover;
147        public boolean offerLookback;
148        public int defaultLookback;
149        public boolean syncChanges;
150        public boolean syncContacts;
151        public boolean syncCalendar;
152        public boolean offerAttachmentPreload;
153        public CharSequence[] syncIntervalStrings;
154        public CharSequence[] syncIntervals;
155        public int defaultSyncInterval;
156
157        public String toString() {
158            StringBuilder sb = new StringBuilder("Protocol: ");
159            sb.append(protocol);
160            sb.append(", ");
161            sb.append(klass != null ? "Local" : "Remote");
162            return sb.toString();
163        }
164    }
165
166    public static EmailServiceProxy getService(Context context, IEmailServiceCallback callback,
167            String protocol) {
168        // Handle the degenerate case here (account might have been deleted)
169        if (protocol == null) {
170            Log.w(Logging.LOG_TAG, "Returning NullService for " + protocol);
171            return new EmailServiceProxy(context, NullService.class, null);
172        }
173        EmailServiceInfo info = getServiceInfo(context, protocol);
174        if (info.klass != null) {
175            return new EmailServiceProxy(context, info.klass, callback);
176        } else {
177            return new EmailServiceProxy(context, info.intentAction, callback);
178        }
179    }
180
181    public static EmailServiceInfo getServiceInfo(Context context, String protocol) {
182        if (sServiceList.isEmpty()) {
183            findServices(context);
184        }
185        for (EmailServiceInfo info: sServiceList) {
186            if (info.protocol.equals(protocol)) {
187                return info;
188            }
189        }
190        return null;
191    }
192
193    public static List<EmailServiceInfo> getServiceInfoList(Context context) {
194        synchronized(sServiceList) {
195            if (sServiceList.isEmpty()) {
196                findServices(context);
197            }
198            return sServiceList;
199        }
200    }
201
202    /**
203     * Parse services.xml file to find our available email services
204     */
205    @SuppressWarnings("unchecked")
206    private static void findServices(Context context) {
207        try {
208            Resources res = context.getResources();
209            XmlResourceParser xml = res.getXml(R.xml.services);
210            int xmlEventType;
211            // walk through senders.xml file.
212            while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
213                if (xmlEventType == XmlResourceParser.START_TAG &&
214                        "emailservice".equals(xml.getName())) {
215                    EmailServiceInfo info = new EmailServiceInfo();
216                    TypedArray ta = res.obtainAttributes(xml, R.styleable.EmailServiceInfo);
217                    info.protocol = ta.getString(R.styleable.EmailServiceInfo_protocol);
218                    info.name = ta.getString(R.styleable.EmailServiceInfo_name);
219                    String klass = ta.getString(R.styleable.EmailServiceInfo_serviceClass);
220                    info.intentAction = ta.getString(R.styleable.EmailServiceInfo_intent);
221                    info.accountType = ta.getString(R.styleable.EmailServiceInfo_accountType);
222                    info.defaultSsl = ta.getBoolean(R.styleable.EmailServiceInfo_defaultSsl, false);
223                    info.port = ta.getInteger(R.styleable.EmailServiceInfo_port, 0);
224                    info.portSsl = ta.getInteger(R.styleable.EmailServiceInfo_portSsl, 0);
225                    info.offerTls = ta.getBoolean(R.styleable.EmailServiceInfo_offerTls, false);
226                    info.offerCerts = ta.getBoolean(R.styleable.EmailServiceInfo_offerCerts, false);
227                    info.offerLocalDeletes =
228                        ta.getBoolean(R.styleable.EmailServiceInfo_offerLocalDeletes, false);
229                    info.defaultLocalDeletes =
230                        ta.getInteger(R.styleable.EmailServiceInfo_defaultLocalDeletes,
231                                Account.DELETE_POLICY_ON_DELETE);
232                    info.offerPrefix =
233                        ta.getBoolean(R.styleable.EmailServiceInfo_offerPrefix, false);
234                    info.usesSmtp = ta.getBoolean(R.styleable.EmailServiceInfo_usesSmtp, false);
235                    info.usesAutodiscover =
236                        ta.getBoolean(R.styleable.EmailServiceInfo_usesAutodiscover, false);
237                    info.offerLookback =
238                        ta.getBoolean(R.styleable.EmailServiceInfo_offerLookback, false);
239                    info.defaultLookback =
240                        ta.getInteger(R.styleable.EmailServiceInfo_defaultLookback,
241                                SyncWindow.SYNC_WINDOW_3_DAYS);
242                    info.syncChanges =
243                        ta.getBoolean(R.styleable.EmailServiceInfo_syncChanges, false);
244                    info.syncContacts =
245                        ta.getBoolean(R.styleable.EmailServiceInfo_syncContacts, false);
246                    info.syncCalendar =
247                        ta.getBoolean(R.styleable.EmailServiceInfo_syncCalendar, false);
248                    info.offerAttachmentPreload =
249                        ta.getBoolean(R.styleable.EmailServiceInfo_offerAttachmentPreload, false);
250                    info.syncIntervalStrings =
251                        ta.getTextArray(R.styleable.EmailServiceInfo_syncIntervalStrings);
252                    info.syncIntervals =
253                        ta.getTextArray(R.styleable.EmailServiceInfo_syncIntervals);
254                    info.defaultSyncInterval =
255                        ta.getInteger(R.styleable.EmailServiceInfo_defaultSyncInterval, 15);
256
257                    // Must have either "class" (local) or "intent" (remote)
258                    if (klass != null) {
259                        try {
260                            info.klass = (Class<? extends Service>) Class.forName(klass);
261                        } catch (ClassNotFoundException e) {
262                            throw new IllegalStateException(
263                                    "Class not found in service descriptor: " + klass);
264                        }
265                    }
266                    if (info.klass == null && info.intentAction == null) {
267                        throw new IllegalStateException(
268                                "No class or intent action specified in service descriptor");
269                    }
270                    if (info.klass != null && info.intentAction != null) {
271                        throw new IllegalStateException(
272                                "Both class and intent action specified in service descriptor");
273                    }
274                    sServiceList.add(info);
275                }
276            }
277        } catch (XmlPullParserException e) {
278            // ignore
279        } catch (IOException e) {
280            // ignore
281        }
282    }
283
284    /**
285     * A no-op service that can be returned for non-existent/null protocols
286     */
287    class NullService implements IEmailService {
288        @Override
289        public IBinder asBinder() {
290            return null;
291        }
292
293        @Override
294        public Bundle validate(HostAuth hostauth) throws RemoteException {
295            return null;
296        }
297
298        @Override
299        public void startSync(long mailboxId, boolean userRequest) throws RemoteException {
300        }
301
302        @Override
303        public void stopSync(long mailboxId) throws RemoteException {
304        }
305
306        @Override
307        public void loadMore(long messageId) throws RemoteException {
308        }
309
310        @Override
311        public void loadAttachment(long attachmentId, boolean background) throws RemoteException {
312        }
313
314        @Override
315        public void updateFolderList(long accountId) throws RemoteException {
316        }
317
318        @Override
319        public boolean createFolder(long accountId, String name) throws RemoteException {
320            return false;
321        }
322
323        @Override
324        public boolean deleteFolder(long accountId, String name) throws RemoteException {
325            return false;
326        }
327
328        @Override
329        public boolean renameFolder(long accountId, String oldName, String newName)
330                throws RemoteException {
331            return false;
332        }
333
334        @Override
335        public void setCallback(IEmailServiceCallback cb) throws RemoteException {
336        }
337
338        @Override
339        public void setLogging(int on) throws RemoteException {
340        }
341
342        @Override
343        public void hostChanged(long accountId) throws RemoteException {
344        }
345
346        @Override
347        public Bundle autoDiscover(String userName, String password) throws RemoteException {
348            return null;
349        }
350
351        @Override
352        public void sendMeetingResponse(long messageId, int response) throws RemoteException {
353        }
354
355        @Override
356        public void deleteAccountPIMData(long accountId) throws RemoteException {
357        }
358
359        @Override
360        public int getApiLevel() throws RemoteException {
361            return Api.LEVEL;
362        }
363
364        @Override
365        public int searchMessages(long accountId, SearchParams params, long destMailboxId)
366                throws RemoteException {
367            return 0;
368        }
369
370        @Override
371        public void sendMail(long accountId) throws RemoteException {
372        }
373
374        @Override
375        public int getCapabilities(long accountId) throws RemoteException {
376            return 0;
377        }
378    }
379}
380