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