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