EmailServiceUtils.java revision cf3b3ae987e73453f2265673a7ba3a72a1a6b4ed
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        EmailServiceInfo info = null;
169        // Handle the degenerate case here (account might have been deleted)
170        if (protocol != null) {
171            info = getServiceInfo(context, protocol);
172        }
173        if (info == null) {
174            Log.w(Logging.LOG_TAG, "Returning NullService for " + protocol);
175            return new EmailServiceProxy(context, NullService.class, null);
176        } else if (info.klass != null) {
177            return new EmailServiceProxy(context, info.klass, callback);
178        } else {
179            return new EmailServiceProxy(context, info.intentAction, callback);
180        }
181    }
182
183    public static EmailServiceInfo getServiceInfo(Context context, String protocol) {
184        if (sServiceList.isEmpty()) {
185            findServices(context);
186        }
187        for (EmailServiceInfo info: sServiceList) {
188            if (info.protocol.equals(protocol)) {
189                return info;
190            }
191        }
192        return null;
193    }
194
195    public static List<EmailServiceInfo> getServiceInfoList(Context context) {
196        synchronized(sServiceList) {
197            if (sServiceList.isEmpty()) {
198                findServices(context);
199            }
200            return sServiceList;
201        }
202    }
203
204    /**
205     * Parse services.xml file to find our available email services
206     */
207    @SuppressWarnings("unchecked")
208    private static void findServices(Context context) {
209        try {
210            Resources res = context.getResources();
211            XmlResourceParser xml = res.getXml(R.xml.services);
212            int xmlEventType;
213            // walk through senders.xml file.
214            while ((xmlEventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {
215                if (xmlEventType == XmlResourceParser.START_TAG &&
216                        "emailservice".equals(xml.getName())) {
217                    EmailServiceInfo info = new EmailServiceInfo();
218                    TypedArray ta = res.obtainAttributes(xml, R.styleable.EmailServiceInfo);
219                    info.protocol = ta.getString(R.styleable.EmailServiceInfo_protocol);
220                    info.name = ta.getString(R.styleable.EmailServiceInfo_name);
221                    String klass = ta.getString(R.styleable.EmailServiceInfo_serviceClass);
222                    info.intentAction = ta.getString(R.styleable.EmailServiceInfo_intent);
223                    info.accountType = ta.getString(R.styleable.EmailServiceInfo_accountType);
224                    info.defaultSsl = ta.getBoolean(R.styleable.EmailServiceInfo_defaultSsl, false);
225                    info.port = ta.getInteger(R.styleable.EmailServiceInfo_port, 0);
226                    info.portSsl = ta.getInteger(R.styleable.EmailServiceInfo_portSsl, 0);
227                    info.offerTls = ta.getBoolean(R.styleable.EmailServiceInfo_offerTls, false);
228                    info.offerCerts = ta.getBoolean(R.styleable.EmailServiceInfo_offerCerts, false);
229                    info.offerLocalDeletes =
230                        ta.getBoolean(R.styleable.EmailServiceInfo_offerLocalDeletes, false);
231                    info.defaultLocalDeletes =
232                        ta.getInteger(R.styleable.EmailServiceInfo_defaultLocalDeletes,
233                                Account.DELETE_POLICY_ON_DELETE);
234                    info.offerPrefix =
235                        ta.getBoolean(R.styleable.EmailServiceInfo_offerPrefix, false);
236                    info.usesSmtp = ta.getBoolean(R.styleable.EmailServiceInfo_usesSmtp, false);
237                    info.usesAutodiscover =
238                        ta.getBoolean(R.styleable.EmailServiceInfo_usesAutodiscover, false);
239                    info.offerLookback =
240                        ta.getBoolean(R.styleable.EmailServiceInfo_offerLookback, false);
241                    info.defaultLookback =
242                        ta.getInteger(R.styleable.EmailServiceInfo_defaultLookback,
243                                SyncWindow.SYNC_WINDOW_3_DAYS);
244                    info.syncChanges =
245                        ta.getBoolean(R.styleable.EmailServiceInfo_syncChanges, false);
246                    info.syncContacts =
247                        ta.getBoolean(R.styleable.EmailServiceInfo_syncContacts, false);
248                    info.syncCalendar =
249                        ta.getBoolean(R.styleable.EmailServiceInfo_syncCalendar, false);
250                    info.offerAttachmentPreload =
251                        ta.getBoolean(R.styleable.EmailServiceInfo_offerAttachmentPreload, false);
252                    info.syncIntervalStrings =
253                        ta.getTextArray(R.styleable.EmailServiceInfo_syncIntervalStrings);
254                    info.syncIntervals =
255                        ta.getTextArray(R.styleable.EmailServiceInfo_syncIntervals);
256                    info.defaultSyncInterval =
257                        ta.getInteger(R.styleable.EmailServiceInfo_defaultSyncInterval, 15);
258
259                    // Must have either "class" (local) or "intent" (remote)
260                    if (klass != null) {
261                        try {
262                            info.klass = (Class<? extends Service>) Class.forName(klass);
263                        } catch (ClassNotFoundException e) {
264                            throw new IllegalStateException(
265                                    "Class not found in service descriptor: " + klass);
266                        }
267                    }
268                    if (info.klass == null && info.intentAction == null) {
269                        throw new IllegalStateException(
270                                "No class or intent action specified in service descriptor");
271                    }
272                    if (info.klass != null && info.intentAction != null) {
273                        throw new IllegalStateException(
274                                "Both class and intent action specified in service descriptor");
275                    }
276                    sServiceList.add(info);
277                }
278            }
279        } catch (XmlPullParserException e) {
280            // ignore
281        } catch (IOException e) {
282            // ignore
283        }
284    }
285
286    /**
287     * A no-op service that can be returned for non-existent/null protocols
288     */
289    class NullService implements IEmailService {
290        @Override
291        public IBinder asBinder() {
292            return null;
293        }
294
295        @Override
296        public Bundle validate(HostAuth hostauth) throws RemoteException {
297            return null;
298        }
299
300        @Override
301        public void startSync(long mailboxId, boolean userRequest) throws RemoteException {
302        }
303
304        @Override
305        public void stopSync(long mailboxId) throws RemoteException {
306        }
307
308        @Override
309        public void loadMore(long messageId) throws RemoteException {
310        }
311
312        @Override
313        public void loadAttachment(long attachmentId, boolean background) throws RemoteException {
314        }
315
316        @Override
317        public void updateFolderList(long accountId) throws RemoteException {
318        }
319
320        @Override
321        public boolean createFolder(long accountId, String name) throws RemoteException {
322            return false;
323        }
324
325        @Override
326        public boolean deleteFolder(long accountId, String name) throws RemoteException {
327            return false;
328        }
329
330        @Override
331        public boolean renameFolder(long accountId, String oldName, String newName)
332                throws RemoteException {
333            return false;
334        }
335
336        @Override
337        public void setCallback(IEmailServiceCallback cb) throws RemoteException {
338        }
339
340        @Override
341        public void setLogging(int on) throws RemoteException {
342        }
343
344        @Override
345        public void hostChanged(long accountId) throws RemoteException {
346        }
347
348        @Override
349        public Bundle autoDiscover(String userName, String password) throws RemoteException {
350            return null;
351        }
352
353        @Override
354        public void sendMeetingResponse(long messageId, int response) throws RemoteException {
355        }
356
357        @Override
358        public void deleteAccountPIMData(long accountId) throws RemoteException {
359        }
360
361        @Override
362        public int getApiLevel() throws RemoteException {
363            return Api.LEVEL;
364        }
365
366        @Override
367        public int searchMessages(long accountId, SearchParams params, long destMailboxId)
368                throws RemoteException {
369            return 0;
370        }
371
372        @Override
373        public void sendMail(long accountId) throws RemoteException {
374        }
375
376        @Override
377        public int getCapabilities(Account acct) throws RemoteException {
378            return 0;
379        }
380    }
381}
382