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