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