PageRenderTime 2192ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/emailcommon/src/com/android/emailcommon/service/EmailServiceProxy.java

https://bitbucket.org/camcory/android_packages_apps_email
Java | 471 lines | 267 code | 37 blank | 167 comment | 33 complexity | 49b51f37c507b8c4685146c3ab97e4f7 MD5 | raw file
  1. /*
  2. * Copyright (C) 2009 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. package com.android.emailcommon.service;
  17. import android.content.Context;
  18. import android.content.Intent;
  19. import android.os.Bundle;
  20. import android.os.IBinder;
  21. import android.os.RemoteException;
  22. import android.util.Log;
  23. import com.android.emailcommon.Api;
  24. import com.android.emailcommon.Device;
  25. import com.android.emailcommon.TempDirectory;
  26. import com.android.emailcommon.mail.MessagingException;
  27. import com.android.emailcommon.provider.HostAuth;
  28. import com.android.emailcommon.provider.Policy;
  29. import java.io.IOException;
  30. /**
  31. * The EmailServiceProxy class provides a simple interface for the UI to call into the various
  32. * EmailService classes (e.g. ExchangeService for EAS). It wraps the service connect/disconnect
  33. * process so that the caller need not be concerned with it.
  34. *
  35. * Use the class like this:
  36. * new EmailServiceProxy(context, class).loadAttachment(attachmentId, callback)
  37. *
  38. * Methods without a return value return immediately (i.e. are asynchronous); methods with a
  39. * return value wait for a result from the Service (i.e. they should not be called from the UI
  40. * thread) with a default timeout of 30 seconds (settable)
  41. *
  42. * An EmailServiceProxy object cannot be reused (trying to do so generates a RemoteException)
  43. */
  44. public class EmailServiceProxy extends ServiceProxy implements IEmailService {
  45. private static final String TAG = "EmailServiceProxy";
  46. // Private intent that will be used to connect to an independent Exchange service
  47. public static final String EXCHANGE_INTENT = "com.android.email.EXCHANGE_INTENT";
  48. public static final String IMAP_INTENT = "com.android.email.IMAP_INTENT";
  49. public static final String AUTO_DISCOVER_BUNDLE_ERROR_CODE = "autodiscover_error_code";
  50. public static final String AUTO_DISCOVER_BUNDLE_HOST_AUTH = "autodiscover_host_auth";
  51. public static final String VALIDATE_BUNDLE_RESULT_CODE = "validate_result_code";
  52. public static final String VALIDATE_BUNDLE_POLICY_SET = "validate_policy_set";
  53. public static final String VALIDATE_BUNDLE_ERROR_MESSAGE = "validate_error_message";
  54. public static final String VALIDATE_BUNDLE_UNSUPPORTED_POLICIES =
  55. "validate_unsupported_policies";
  56. private final IEmailServiceCallback mCallback;
  57. private Object mReturn = null;
  58. private IEmailService mService;
  59. private final boolean isRemote;
  60. // Standard debugging
  61. public static final int DEBUG_BIT = 1;
  62. // Verbose (parser) logging
  63. public static final int DEBUG_VERBOSE_BIT = 2;
  64. // File (SD card) logging
  65. public static final int DEBUG_FILE_BIT = 4;
  66. // Enable strict mode
  67. public static final int DEBUG_ENABLE_STRICT_MODE = 8;
  68. // The first two constructors are used with local services that can be referenced by class
  69. public EmailServiceProxy(Context _context, Class<?> _class) {
  70. this(_context, _class, null);
  71. }
  72. public EmailServiceProxy(Context _context, Class<?> _class, IEmailServiceCallback _callback) {
  73. super(_context, new Intent(_context, _class));
  74. mCallback = _callback;
  75. isRemote = false;
  76. }
  77. // The following two constructors are used with remote services that must be referenced by
  78. // a known action or by a prebuilt intent
  79. public EmailServiceProxy(Context _context, Intent _intent, IEmailServiceCallback _callback) {
  80. super(_context, _intent);
  81. try {
  82. Device.getDeviceId(_context);
  83. TempDirectory.setTempDirectory(_context);
  84. } catch (IOException e) {
  85. }
  86. mCallback = _callback;
  87. isRemote = true;
  88. }
  89. public EmailServiceProxy(Context _context, String _action, IEmailServiceCallback _callback) {
  90. super(_context, new Intent(_action));
  91. try {
  92. Device.getDeviceId(_context);
  93. TempDirectory.setTempDirectory(_context);
  94. } catch (IOException e) {
  95. }
  96. mCallback = _callback;
  97. isRemote = true;
  98. }
  99. @Override
  100. public void onConnected(IBinder binder) {
  101. mService = IEmailService.Stub.asInterface(binder);
  102. }
  103. public boolean isRemote() {
  104. return isRemote;
  105. }
  106. @Override
  107. public int getApiLevel() {
  108. return Api.LEVEL;
  109. }
  110. /**
  111. * Request an attachment to be loaded; the service MUST give higher priority to
  112. * non-background loading. The service MUST use the loadAttachmentStatus callback when
  113. * loading has started and stopped and SHOULD send callbacks with progress information if
  114. * possible.
  115. *
  116. * @param attachmentId the id of the attachment record
  117. * @param background whether or not this request corresponds to a background action (i.e.
  118. * prefetch) vs a foreground action (user request)
  119. */
  120. @Override
  121. public void loadAttachment(final long attachmentId, final boolean background)
  122. throws RemoteException {
  123. setTask(new ProxyTask() {
  124. @Override
  125. public void run() throws RemoteException {
  126. try {
  127. if (mCallback != null) mService.setCallback(mCallback);
  128. mService.loadAttachment(attachmentId, background);
  129. } catch (RemoteException e) {
  130. try {
  131. // Try to send a callback (if set)
  132. if (mCallback != null) {
  133. mCallback.loadAttachmentStatus(-1, attachmentId,
  134. EmailServiceStatus.REMOTE_EXCEPTION, 0);
  135. }
  136. } catch (RemoteException e1) {
  137. }
  138. }
  139. }
  140. }, "loadAttachment");
  141. }
  142. /**
  143. * Request the sync of a mailbox; the service MUST send the syncMailboxStatus callback
  144. * indicating "starting" and "finished" (or error), regardless of whether the mailbox is
  145. * actually syncable.
  146. *
  147. * @param mailboxId the id of the mailbox record
  148. * @param userRequest whether or not the user specifically asked for the sync
  149. */
  150. @Override
  151. public void startSync(final long mailboxId, final boolean userRequest) throws RemoteException {
  152. setTask(new ProxyTask() {
  153. @Override
  154. public void run() throws RemoteException {
  155. if (mCallback != null) mService.setCallback(mCallback);
  156. mService.startSync(mailboxId, userRequest);
  157. }
  158. }, "startSync");
  159. }
  160. /**
  161. * Request the immediate termination of a mailbox sync. Although the service is not required to
  162. * acknowledge this request, it MUST send a "finished" (or error) syncMailboxStatus callback if
  163. * the sync was started via the startSync service call.
  164. *
  165. * @param mailboxId the id of the mailbox record
  166. * @param userRequest whether or not the user specifically asked for the sync
  167. */
  168. @Override
  169. public void stopSync(final long mailboxId) throws RemoteException {
  170. setTask(new ProxyTask() {
  171. @Override
  172. public void run() throws RemoteException {
  173. if (mCallback != null) mService.setCallback(mCallback);
  174. mService.stopSync(mailboxId);
  175. }
  176. }, "stopSync");
  177. }
  178. /**
  179. * Validate a user account, given a protocol, host address, port, ssl status, and credentials.
  180. * The result of this call is returned in a Bundle which MUST include a result code and MAY
  181. * include a PolicySet that is required by the account. A successful validation implies a host
  182. * address that serves the specified protocol and credentials sufficient to be authorized
  183. * by the server to do so.
  184. *
  185. * @param hostAuth the hostauth object to validate
  186. * @return a Bundle as described above
  187. */
  188. @Override
  189. public Bundle validate(final HostAuth hostAuth) throws RemoteException {
  190. setTask(new ProxyTask() {
  191. @Override
  192. public void run() throws RemoteException{
  193. if (mCallback != null) mService.setCallback(mCallback);
  194. mReturn = mService.validate(hostAuth);
  195. }
  196. }, "validate");
  197. waitForCompletion();
  198. if (mReturn == null) {
  199. Bundle bundle = new Bundle();
  200. bundle.putInt(VALIDATE_BUNDLE_RESULT_CODE, MessagingException.UNSPECIFIED_EXCEPTION);
  201. return bundle;
  202. } else {
  203. Bundle bundle = (Bundle) mReturn;
  204. bundle.setClassLoader(Policy.class.getClassLoader());
  205. Log.v(TAG, "validate returns " + bundle.getInt(VALIDATE_BUNDLE_RESULT_CODE));
  206. return bundle;
  207. }
  208. }
  209. /**
  210. * Attempt to determine a user's host address and credentials from an email address and
  211. * password. The result is returned in a Bundle which MUST include an error code and MAY (on
  212. * success) include a HostAuth record sufficient to enable the service to validate the user's
  213. * account.
  214. *
  215. * @param userName the user's email address
  216. * @param password the user's password
  217. * @return a Bundle as described above
  218. */
  219. @Override
  220. public Bundle autoDiscover(final String userName, final String password)
  221. throws RemoteException {
  222. setTask(new ProxyTask() {
  223. @Override
  224. public void run() throws RemoteException{
  225. if (mCallback != null) mService.setCallback(mCallback);
  226. mReturn = mService.autoDiscover(userName, password);
  227. }
  228. }, "autoDiscover");
  229. waitForCompletion();
  230. if (mReturn == null) {
  231. return null;
  232. } else {
  233. Bundle bundle = (Bundle) mReturn;
  234. bundle.setClassLoader(HostAuth.class.getClassLoader());
  235. Log.v(TAG, "autoDiscover returns " + bundle.getInt(AUTO_DISCOVER_BUNDLE_ERROR_CODE));
  236. return bundle;
  237. }
  238. }
  239. /**
  240. * Request that the service reload the folder list for the specified account. The service
  241. * MUST use the syncMailboxListStatus callback to indicate "starting" and "finished"
  242. *
  243. * @param accoundId the id of the account whose folder list is to be updated
  244. */
  245. @Override
  246. public void updateFolderList(final long accountId) throws RemoteException {
  247. setTask(new ProxyTask() {
  248. @Override
  249. public void run() throws RemoteException {
  250. if (mCallback != null) mService.setCallback(mCallback);
  251. mService.updateFolderList(accountId);
  252. }
  253. }, "updateFolderList");
  254. }
  255. /**
  256. * Specify the debug flags selected by the user. The service SHOULD log debug information as
  257. * requested.
  258. *
  259. * @param flags an integer whose bits represent logging flags as defined in DEBUG_* flags above
  260. */
  261. @Override
  262. public void setLogging(final int flags) throws RemoteException {
  263. setTask(new ProxyTask() {
  264. @Override
  265. public void run() throws RemoteException {
  266. if (mCallback != null) mService.setCallback(mCallback);
  267. mService.setLogging(flags);
  268. }
  269. }, "setLogging");
  270. }
  271. /**
  272. * Set the global callback object to be used by the service; the service MUST always use the
  273. * most recently set callback object
  274. *
  275. * @param cb a callback object through which all service callbacks are executed
  276. */
  277. @Override
  278. public void setCallback(final IEmailServiceCallback cb) throws RemoteException {
  279. setTask(new ProxyTask() {
  280. @Override
  281. public void run() throws RemoteException {
  282. mService.setCallback(cb);
  283. }
  284. }, "setCallback");
  285. }
  286. /**
  287. * Alert the sync adapter that the account's host information has (or may have) changed; the
  288. * service MUST stop all in-process or pending syncs, clear error states related to the
  289. * account and its mailboxes, and restart necessary sync adapters (e.g. pushed mailboxes)
  290. *
  291. * @param accountId the id of the account whose host information has changed
  292. */
  293. @Override
  294. public void hostChanged(final long accountId) throws RemoteException {
  295. setTask(new ProxyTask() {
  296. @Override
  297. public void run() throws RemoteException {
  298. mService.hostChanged(accountId);
  299. }
  300. }, "hostChanged");
  301. }
  302. /**
  303. * Send a meeting response for the specified message
  304. *
  305. * @param messageId the id of the message containing the meeting request
  306. * @param response the response code, as defined in EmailServiceConstants
  307. */
  308. @Override
  309. public void sendMeetingResponse(final long messageId, final int response)
  310. throws RemoteException {
  311. setTask(new ProxyTask() {
  312. @Override
  313. public void run() throws RemoteException {
  314. if (mCallback != null) mService.setCallback(mCallback);
  315. mService.sendMeetingResponse(messageId, response);
  316. }
  317. }, "sendMeetingResponse");
  318. }
  319. /**
  320. * Request the sync adapter to load a complete message
  321. *
  322. * @param messageId the id of the message to be loaded
  323. */
  324. @Override
  325. public void loadMore(final long messageId) throws RemoteException {
  326. setTask(new ProxyTask() {
  327. @Override
  328. public void run() throws RemoteException {
  329. if (mCallback != null) mService.setCallback(mCallback);
  330. mService.loadMore(messageId);
  331. }
  332. }, "startSync");
  333. }
  334. /**
  335. * Not yet used
  336. *
  337. * @param accountId the account in which the folder is to be created
  338. * @param name the name of the folder to be created
  339. */
  340. @Override
  341. public boolean createFolder(long accountId, String name) throws RemoteException {
  342. return false;
  343. }
  344. /**
  345. * Not yet used
  346. *
  347. * @param accountId the account in which the folder resides
  348. * @param name the name of the folder to be deleted
  349. */
  350. @Override
  351. public boolean deleteFolder(long accountId, String name) throws RemoteException {
  352. return false;
  353. }
  354. /**
  355. * Not yet used
  356. *
  357. * @param accountId the account in which the folder resides
  358. * @param oldName the name of the existing folder
  359. * @param newName the new name for the folder
  360. */
  361. @Override
  362. public boolean renameFolder(long accountId, String oldName, String newName)
  363. throws RemoteException {
  364. return false;
  365. }
  366. /**
  367. * Request the service to delete the account's PIM (personal information management) data. This
  368. * data includes any data that is 1) associated with the account and 2) created/stored by the
  369. * service or its sync adapters and 3) not stored in the EmailProvider database (e.g. contact
  370. * and calendar information).
  371. *
  372. * @param accountId the account whose data is to be deleted
  373. */
  374. @Override
  375. public void deleteAccountPIMData(final long accountId) throws RemoteException {
  376. setTask(new ProxyTask() {
  377. @Override
  378. public void run() throws RemoteException {
  379. mService.deleteAccountPIMData(accountId);
  380. }
  381. }, "deleteAccountPIMData");
  382. }
  383. /**
  384. * PRELIMINARY
  385. * Search for messages given a query string. The string is interpreted as the logical AND of
  386. * terms separated by white space. The search is performed on the specified mailbox in the
  387. * specified account (including subfolders, as specified by the includeSubfolders parameter).
  388. * At most numResults messages matching the query term(s) will be added to the mailbox specified
  389. * as destMailboxId. If mailboxId is -1, the entire account will be searched. If firstResult is
  390. * specified and non-zero, results will be added starting with the firstResult'th match (i.e.
  391. * for the continuation of a previous search)
  392. *
  393. * @param accountId the id of the account to be searched
  394. * @param searchParams the search specification
  395. * @param destMailboxId the id of the mailbox into which search results are appended
  396. * @return the total number of matches for this search (regardless of how many were requested)
  397. */
  398. @Override
  399. public int searchMessages(final long accountId, final SearchParams searchParams,
  400. final long destMailboxId) throws RemoteException {
  401. setTask(new ProxyTask() {
  402. @Override
  403. public void run() throws RemoteException{
  404. if (mCallback != null) mService.setCallback(mCallback);
  405. mReturn = mService.searchMessages(accountId, searchParams, destMailboxId);
  406. }
  407. }, "searchMessages");
  408. waitForCompletion();
  409. if (mReturn == null) {
  410. return 0;
  411. } else {
  412. return (Integer)mReturn;
  413. }
  414. }
  415. /**
  416. * Request the service to send mail in the specified account's Outbox
  417. *
  418. * @param accountId the account whose outgoing mail should be sent
  419. */
  420. @Override
  421. public void sendMail(final long accountId) throws RemoteException {
  422. setTask(new ProxyTask() {
  423. @Override
  424. public void run() throws RemoteException{
  425. if (mCallback != null) mService.setCallback(mCallback);
  426. mService.sendMail(accountId);
  427. }
  428. }, "sendMail");
  429. }
  430. @Override
  431. public IBinder asBinder() {
  432. return null;
  433. }
  434. }