Merge "Handle Exchange meeting invitation responses"
This commit is contained in:
commit
3ef6b0493e
@ -551,7 +551,7 @@ public class Controller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a single attachment entry from the DB given its id.
|
* Delete a single attachment entry from the DB given its id.
|
||||||
* Does not delete any eventual associated files.
|
* Does not delete any eventual associated files.
|
||||||
*/
|
*/
|
||||||
public void deleteAttachment(long attachmentId) {
|
public void deleteAttachment(long attachmentId) {
|
||||||
ContentResolver resolver = mProviderContext.getContentResolver();
|
ContentResolver resolver = mProviderContext.getContentResolver();
|
||||||
@ -684,6 +684,29 @@ public class Controller {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond to a meeting invitation.
|
||||||
|
*
|
||||||
|
* @param messageId the id of the invitation being responded to
|
||||||
|
* @param response the code representing the response to the invitation
|
||||||
|
* @callback the Controller callback by which results will be reported (currently not defined)
|
||||||
|
*/
|
||||||
|
public void sendMeetingResponse(final long messageId, final int response,
|
||||||
|
final Result callback) {
|
||||||
|
// Split here for target type (Service or MessagingController)
|
||||||
|
IEmailService service = getServiceForMessage(messageId);
|
||||||
|
if (service != null) {
|
||||||
|
// Service implementation
|
||||||
|
try {
|
||||||
|
service.sendMeetingResponse(messageId, response);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// TODO Change exception handling to be consistent with however this method
|
||||||
|
// is implemented for other protocols
|
||||||
|
Log.e("onDownloadAttachment", "RemoteException", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request that an attachment be loaded. It will be stored at a location controlled
|
* Request that an attachment be loaded. It will be stored at a location controlled
|
||||||
* by the AttachmentProvider.
|
* by the AttachmentProvider.
|
||||||
|
@ -31,6 +31,7 @@ import com.android.email.provider.EmailContent.Attachment;
|
|||||||
import com.android.email.provider.EmailContent.Body;
|
import com.android.email.provider.EmailContent.Body;
|
||||||
import com.android.email.provider.EmailContent.BodyColumns;
|
import com.android.email.provider.EmailContent.BodyColumns;
|
||||||
import com.android.email.provider.EmailContent.Message;
|
import com.android.email.provider.EmailContent.Message;
|
||||||
|
import com.android.exchange.EmailServiceConstants;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
@ -64,7 +65,6 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.Window;
|
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
@ -676,6 +676,16 @@ public class MessageView extends Activity implements OnClickListener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE
|
||||||
|
// This is a placeholder for code used to accept a meeting invitation, and would presumably
|
||||||
|
// be called in response to a button press or menu selection
|
||||||
|
// The appropriate EmailServiceConstant would be changed to implement "decline" and
|
||||||
|
// "tentative" responses
|
||||||
|
private void onAccept() {
|
||||||
|
mController.sendMeetingResponse(mMessageId, EmailServiceConstants.MEETING_REQUEST_ACCEPTED,
|
||||||
|
mControllerCallback);
|
||||||
|
}
|
||||||
|
|
||||||
private void onDownloadAttachment(AttachmentInfo attachment) {
|
private void onDownloadAttachment(AttachmentInfo attachment) {
|
||||||
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
|
||||||
/*
|
/*
|
||||||
|
@ -542,12 +542,18 @@ public abstract class EmailContent {
|
|||||||
public static final int FLAG_LOADED_DELETED = 3;
|
public static final int FLAG_LOADED_DELETED = 3;
|
||||||
|
|
||||||
// Bits used in mFlags
|
// Bits used in mFlags
|
||||||
// These three states are mutually exclusive, and indicate whether the message is an
|
// The following three states are mutually exclusive, and indicate whether the message is an
|
||||||
// original, a reply, or a forward
|
// original, a reply, or a forward
|
||||||
public static final int FLAG_TYPE_ORIGINAL = 0;
|
public static final int FLAG_TYPE_ORIGINAL = 0;
|
||||||
public static final int FLAG_TYPE_REPLY = 1<<0;
|
public static final int FLAG_TYPE_REPLY = 1<<0;
|
||||||
public static final int FLAG_TYPE_FORWARD = 1<<1;
|
public static final int FLAG_TYPE_FORWARD = 1<<1;
|
||||||
public static final int FLAG_TYPE_MASK = FLAG_TYPE_REPLY | FLAG_TYPE_FORWARD;
|
public static final int FLAG_TYPE_MASK = FLAG_TYPE_REPLY | FLAG_TYPE_FORWARD;
|
||||||
|
// The following flags indicate messages that are determined to be meeting related
|
||||||
|
// (e.g. invites)
|
||||||
|
public static final int FLAG_MEETING_INVITE = 1<<2;
|
||||||
|
public static final int FLAG_MEETING_CANCEL_NOTICE = 1<<3;
|
||||||
|
public static final int FLAG_MEETING_MASK =
|
||||||
|
FLAG_MEETING_INVITE | FLAG_MEETING_CANCEL_NOTICE;
|
||||||
|
|
||||||
public Message() {
|
public Message() {
|
||||||
mBaseUri = CONTENT_URI;
|
mBaseUri = CONTENT_URI;
|
||||||
|
@ -287,6 +287,18 @@ public class EmailServiceProxy implements IEmailService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendMeetingResponse(final long messageId, final int response) throws RemoteException {
|
||||||
|
setTask(new Runnable () {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
if (mCallback != null) mService.setCallback(mCallback);
|
||||||
|
mService.sendMeetingResponse(messageId, response);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public void loadMore(long messageId) throws RemoteException {
|
public void loadMore(long messageId) throws RemoteException {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
}
|
}
|
||||||
|
@ -76,8 +76,8 @@ public abstract class AbstractSyncService implements Runnable {
|
|||||||
protected Object mSynchronizer = new Object();
|
protected Object mSynchronizer = new Object();
|
||||||
|
|
||||||
protected volatile long mRequestTime = 0;
|
protected volatile long mRequestTime = 0;
|
||||||
protected ArrayList<PartRequest> mPartRequests = new ArrayList<PartRequest>();
|
protected ArrayList<Request> mRequests = new ArrayList<Request>();
|
||||||
protected PartRequest mPendingPartRequest = null;
|
protected PartRequest mPendingRequest = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sent by SyncManager to request that the service stop itself cleanly
|
* Sent by SyncManager to request that the service stop itself cleanly
|
||||||
@ -282,54 +282,23 @@ public abstract class AbstractSyncService implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PartRequest handling (common functionality)
|
* Request handling (common functionality)
|
||||||
* Can be overridden if desired, but IMAP/EAS both use the next three methods as-is
|
* Can be overridden if desired
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public void addPartRequest(PartRequest req) {
|
public void addRequest(Request req) {
|
||||||
synchronized (mPartRequests) {
|
synchronized (mRequests) {
|
||||||
mPartRequests.add(req);
|
mRequests.add(req);
|
||||||
mRequestTime = System.currentTimeMillis();
|
mRequestTime = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePartRequest(PartRequest req) {
|
public void removeRequest(Request req) {
|
||||||
synchronized (mPartRequests) {
|
synchronized (mRequests) {
|
||||||
mPartRequests.remove(req);
|
mRequests.remove(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PartRequest hasPartRequest(long emailId, String part) {
|
|
||||||
synchronized (mPartRequests) {
|
|
||||||
for (PartRequest pr : mPartRequests) {
|
|
||||||
if (pr.emailId == emailId && pr.loc.equals(part))
|
|
||||||
return pr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cancelPartRequest is sent in response to user input to stop an attachment load
|
|
||||||
// that is in progress. This will almost certainly require code overriding the base
|
|
||||||
// functionality, as sockets may need to be closed, etc. and this functionality will be
|
|
||||||
// service dependent. This returns the canceled PartRequest or null
|
|
||||||
public PartRequest cancelPartRequest(long emailId, String part) {
|
|
||||||
synchronized (mPartRequests) {
|
|
||||||
PartRequest p = null;
|
|
||||||
for (PartRequest pr : mPartRequests) {
|
|
||||||
if (pr.emailId == emailId && pr.loc.equals(part)) {
|
|
||||||
p = pr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (p != null) {
|
|
||||||
mPartRequests.remove(p);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience method wrapping calls to retrieve columns from a single row, via EmailProvider.
|
* Convenience method wrapping calls to retrieve columns from a single row, via EmailProvider.
|
||||||
* The arguments are exactly the same as to contentResolver.query(). Results are returned in
|
* The arguments are exactly the same as to contentResolver.query(). Results are returned in
|
||||||
|
31
src/com/android/exchange/EasAuthenticationException.java
Normal file
31
src/com/android/exchange/EasAuthenticationException.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.exchange;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this to be able to distinguish login (authentication) failures from other I/O
|
||||||
|
* exceptions during a sync, as they are handled very differently.
|
||||||
|
*/
|
||||||
|
public class EasAuthenticationException extends IOException {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
EasAuthenticationException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ import com.android.exchange.adapter.AccountSyncAdapter;
|
|||||||
import com.android.exchange.adapter.ContactsSyncAdapter;
|
import com.android.exchange.adapter.ContactsSyncAdapter;
|
||||||
import com.android.exchange.adapter.EmailSyncAdapter;
|
import com.android.exchange.adapter.EmailSyncAdapter;
|
||||||
import com.android.exchange.adapter.FolderSyncParser;
|
import com.android.exchange.adapter.FolderSyncParser;
|
||||||
|
import com.android.exchange.adapter.MeetingResponseParser;
|
||||||
import com.android.exchange.adapter.PingParser;
|
import com.android.exchange.adapter.PingParser;
|
||||||
import com.android.exchange.adapter.Serializer;
|
import com.android.exchange.adapter.Serializer;
|
||||||
import com.android.exchange.adapter.Tags;
|
import com.android.exchange.adapter.Tags;
|
||||||
@ -628,7 +629,7 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
protected void getAttachment(PartRequest req) throws IOException {
|
protected void getAttachment(PartRequest req) throws IOException {
|
||||||
Attachment att = req.att;
|
Attachment att = req.mAttachment;
|
||||||
Message msg = Message.restoreMessageWithId(mContext, att.mMessageKey);
|
Message msg = Message.restoreMessageWithId(mContext, att.mMessageKey);
|
||||||
doProgressCallback(msg.mId, att.mId, 0);
|
doProgressCallback(msg.mId, att.mId, 0);
|
||||||
|
|
||||||
@ -640,9 +641,9 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
HttpEntity e = res.getEntity();
|
HttpEntity e = res.getEntity();
|
||||||
int len = (int)e.getContentLength();
|
int len = (int)e.getContentLength();
|
||||||
InputStream is = res.getEntity().getContent();
|
InputStream is = res.getEntity().getContent();
|
||||||
File f = (req.destination != null)
|
File f = (req.mDestination != null)
|
||||||
? new File(req.destination)
|
? new File(req.mDestination)
|
||||||
: createUniqueFileInternal(req.destination, att.mFileName);
|
: createUniqueFileInternal(req.mDestination, att.mFileName);
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
// Ensure that the target directory exists
|
// Ensure that the target directory exists
|
||||||
File destDir = f.getParentFile();
|
File destDir = f.getParentFile();
|
||||||
@ -654,7 +655,7 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
// len < 0 means "chunked" transfer-encoding
|
// len < 0 means "chunked" transfer-encoding
|
||||||
if (len != 0) {
|
if (len != 0) {
|
||||||
try {
|
try {
|
||||||
mPendingPartRequest = req;
|
mPendingRequest = req;
|
||||||
byte[] bytes = new byte[CHUNK_SIZE];
|
byte[] bytes = new byte[CHUNK_SIZE];
|
||||||
int length = len;
|
int length = len;
|
||||||
// Loop terminates 1) when EOF is reached or 2) if an IOException occurs
|
// Loop terminates 1) when EOF is reached or 2) if an IOException occurs
|
||||||
@ -689,7 +690,7 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
mPendingPartRequest = null;
|
mPendingRequest = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
os.flush();
|
os.flush();
|
||||||
@ -697,8 +698,8 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
|
|
||||||
// EmailProvider will throw an exception if we try to update an unsaved attachment
|
// EmailProvider will throw an exception if we try to update an unsaved attachment
|
||||||
if (att.isSaved()) {
|
if (att.isSaved()) {
|
||||||
String contentUriString = (req.contentUriString != null)
|
String contentUriString = (req.mContentUriString != null)
|
||||||
? req.contentUriString
|
? req.mContentUriString
|
||||||
: "file://" + f.getAbsolutePath();
|
: "file://" + f.getAbsolutePath();
|
||||||
ContentValues cv = new ContentValues();
|
ContentValues cv = new ContentValues();
|
||||||
cv.put(AttachmentColumns.CONTENT_URI, contentUriString);
|
cv.put(AttachmentColumns.CONTENT_URI, contentUriString);
|
||||||
@ -711,6 +712,37 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Responds to a meeting request. The MeetingResponseRequest is basically our
|
||||||
|
* wrapper for the meetingResponse service call
|
||||||
|
* @param req the request (message id and response code)
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
protected void sendMeetingResponse(MeetingResponseRequest req) throws IOException {
|
||||||
|
Message msg = Message.restoreMessageWithId(mContext, req.mMessageId);
|
||||||
|
Serializer s = new Serializer();
|
||||||
|
s.start(Tags.MREQ_MEETING_RESPONSE).start(Tags.MREQ_REQUEST);
|
||||||
|
s.data(Tags.MREQ_USER_RESPONSE, Integer.toString(req.mResponse));
|
||||||
|
s.data(Tags.MREQ_COLLECTION_ID, Long.toString(msg.mMailboxKey));
|
||||||
|
s.data(Tags.MREQ_REQ_ID, msg.mServerId);
|
||||||
|
s.end().end().done();
|
||||||
|
HttpResponse res = sendHttpClientPost("MeetingResponse", s.toByteArray());
|
||||||
|
int status = res.getStatusLine().getStatusCode();
|
||||||
|
if (status == HttpStatus.SC_OK) {
|
||||||
|
HttpEntity e = res.getEntity();
|
||||||
|
int len = (int)e.getContentLength();
|
||||||
|
InputStream is = res.getEntity().getContent();
|
||||||
|
if (len != 0) {
|
||||||
|
new MeetingResponseParser(is, this).parse();
|
||||||
|
}
|
||||||
|
} else if (isAuthError(status)) {
|
||||||
|
throw new EasAuthenticationException();
|
||||||
|
} else {
|
||||||
|
userLog("Meeting response request failed, code: " + status);
|
||||||
|
throw new IOException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
private String makeUriString(String cmd, String extra) throws IOException {
|
private String makeUriString(String cmd, String extra) throws IOException {
|
||||||
// Cache the authentication string and the command string
|
// Cache the authentication string and the command string
|
||||||
@ -1323,18 +1355,29 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now, handle various requests
|
||||||
while (true) {
|
while (true) {
|
||||||
PartRequest req = null;
|
Request req = null;
|
||||||
synchronized (mPartRequests) {
|
synchronized (mRequests) {
|
||||||
if (mPartRequests.isEmpty()) {
|
if (mRequests.isEmpty()) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
req = mPartRequests.get(0);
|
req = mRequests.get(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getAttachment(req);
|
|
||||||
synchronized(mPartRequests) {
|
// Our two request types are PartRequest (loading attachment) and
|
||||||
mPartRequests.remove(req);
|
// MeetingResponseRequest (respond to a meeting request)
|
||||||
|
if (req instanceof PartRequest) {
|
||||||
|
getAttachment((PartRequest)req);
|
||||||
|
} else if (req instanceof MeetingResponseRequest) {
|
||||||
|
sendMeetingResponse((MeetingResponseRequest)req);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's an exception handling the request, we'll throw it
|
||||||
|
// Otherwise, we remove the request
|
||||||
|
synchronized(mRequests) {
|
||||||
|
mRequests.remove(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1465,6 +1508,9 @@ public class EasSyncService extends AbstractSyncService {
|
|||||||
sync(target);
|
sync(target);
|
||||||
} while (mRequestTime != 0);
|
} while (mRequestTime != 0);
|
||||||
}
|
}
|
||||||
|
} catch (EasAuthenticationException e) {
|
||||||
|
userLog("Caught authentication error");
|
||||||
|
mExitStatus = EXIT_LOGIN_FAILURE;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
String message = e.getMessage();
|
String message = e.getMessage();
|
||||||
userLog("Caught IOException: ", (message == null) ? "No message" : message);
|
userLog("Caught IOException: ", (message == null) ? "No message" : message);
|
||||||
|
23
src/com/android/exchange/EmailServiceConstants.java
Normal file
23
src/com/android/exchange/EmailServiceConstants.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.exchange;
|
||||||
|
|
||||||
|
public class EmailServiceConstants {
|
||||||
|
public static final int MEETING_REQUEST_ACCEPTED = 1;
|
||||||
|
public static final int MEETING_REQUEST_TENTATIVE = 2;
|
||||||
|
public static final int MEETING_REQUEST_DECLINED = 3;
|
||||||
|
}
|
@ -43,4 +43,6 @@ interface IEmailService {
|
|||||||
void hostChanged(long accountId);
|
void hostChanged(long accountId);
|
||||||
|
|
||||||
Bundle autoDiscover(String userName, String password);
|
Bundle autoDiscover(String userName, String password);
|
||||||
|
|
||||||
|
void sendMeetingResponse(long messageId, int response);
|
||||||
}
|
}
|
29
src/com/android/exchange/MeetingResponseRequest.java
Normal file
29
src/com/android/exchange/MeetingResponseRequest.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.exchange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MeetingResponseRequest is the EAS wrapper for responding to meeting requests.
|
||||||
|
*/
|
||||||
|
public class MeetingResponseRequest extends Request {
|
||||||
|
public int mResponse;
|
||||||
|
|
||||||
|
MeetingResponseRequest(long messageId, int response) {
|
||||||
|
mMessageId = messageId;
|
||||||
|
mResponse = response;
|
||||||
|
}
|
||||||
|
}
|
@ -24,24 +24,21 @@ import com.android.email.provider.EmailContent.Attachment;
|
|||||||
* the attachment to be loaded, it also contains the callback to be used for status/progress
|
* the attachment to be loaded, it also contains the callback to be used for status/progress
|
||||||
* updates to the UI.
|
* updates to the UI.
|
||||||
*/
|
*/
|
||||||
public class PartRequest {
|
public class PartRequest extends Request {
|
||||||
public long timeStamp;
|
public Attachment mAttachment;
|
||||||
public long emailId;
|
public String mDestination;
|
||||||
public Attachment att;
|
public String mContentUriString;
|
||||||
public String destination;
|
public String mLocation;
|
||||||
public String contentUriString;
|
|
||||||
public String loc;
|
|
||||||
|
|
||||||
public PartRequest(Attachment _att) {
|
public PartRequest(Attachment _att) {
|
||||||
timeStamp = System.currentTimeMillis();
|
mMessageId = _att.mMessageKey;
|
||||||
emailId = _att.mMessageKey;
|
mAttachment = _att;
|
||||||
att = _att;
|
mLocation = mAttachment.mLocation;
|
||||||
loc = att.mLocation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PartRequest(Attachment _att, String _destination, String _contentUriString) {
|
public PartRequest(Attachment _att, String _destination, String _contentUriString) {
|
||||||
this(_att);
|
this(_att);
|
||||||
destination = _destination;
|
mDestination = _destination;
|
||||||
contentUriString = _contentUriString;
|
mContentUriString = _contentUriString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
27
src/com/android/exchange/Request.java
Normal file
27
src/com/android/exchange/Request.java
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.exchange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests for mailbox actions are handled by subclasses of this abstract class.
|
||||||
|
* Two subclasses are now defined: PartRequest (attachment load) and MeetingResponseRequest
|
||||||
|
* (respond to a meeting invitation)
|
||||||
|
*/
|
||||||
|
public abstract class Request {
|
||||||
|
public long mTimeStamp = System.currentTimeMillis();
|
||||||
|
public long mMessageId;
|
||||||
|
}
|
@ -312,7 +312,7 @@ public class SyncManager extends Service implements Runnable {
|
|||||||
public void loadAttachment(long attachmentId, String destinationFile,
|
public void loadAttachment(long attachmentId, String destinationFile,
|
||||||
String contentUriString) throws RemoteException {
|
String contentUriString) throws RemoteException {
|
||||||
Attachment att = Attachment.restoreAttachmentWithId(SyncManager.this, attachmentId);
|
Attachment att = Attachment.restoreAttachmentWithId(SyncManager.this, attachmentId);
|
||||||
partRequest(new PartRequest(att, destinationFile, contentUriString));
|
sendMessageRequest(new PartRequest(att, destinationFile, contentUriString));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateFolderList(long accountId) throws RemoteException {
|
public void updateFolderList(long accountId) throws RemoteException {
|
||||||
@ -348,8 +348,11 @@ public class SyncManager extends Service implements Runnable {
|
|||||||
Eas.setUserDebug(on);
|
Eas.setUserDebug(on);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendMeetingResponse(long messageId, int response) throws RemoteException {
|
||||||
|
sendMessageRequest(new MeetingResponseRequest(messageId, response));
|
||||||
|
}
|
||||||
|
|
||||||
public void loadMore(long messageId) throws RemoteException {
|
public void loadMore(long messageId) throws RemoteException {
|
||||||
// TODO Auto-generated method stub
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following three methods are not implemented in this version
|
// The following three methods are not implemented in this version
|
||||||
@ -1338,7 +1341,7 @@ public class SyncManager extends Service implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startService(Mailbox m, int reason, PartRequest req) {
|
private void startService(Mailbox m, int reason, Request req) {
|
||||||
// Don't sync if there's no connectivity
|
// Don't sync if there's no connectivity
|
||||||
if (sConnectivityHold) return;
|
if (sConnectivityHold) return;
|
||||||
synchronized (sSyncToken) {
|
synchronized (sSyncToken) {
|
||||||
@ -1351,7 +1354,7 @@ public class SyncManager extends Service implements Runnable {
|
|||||||
if (!((EasSyncService)service).mIsValid) return;
|
if (!((EasSyncService)service).mIsValid) return;
|
||||||
service.mSyncReason = reason;
|
service.mSyncReason = reason;
|
||||||
if (req != null) {
|
if (req != null) {
|
||||||
service.addPartRequest(req);
|
service.addRequest(req);
|
||||||
}
|
}
|
||||||
startService(service, m);
|
startService(service, m);
|
||||||
}
|
}
|
||||||
@ -1726,9 +1729,9 @@ public class SyncManager extends Service implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static public void partRequest(PartRequest req) {
|
static public void sendMessageRequest(Request req) {
|
||||||
if (INSTANCE == null) return;
|
if (INSTANCE == null) return;
|
||||||
Message msg = Message.restoreMessageWithId(INSTANCE, req.emailId);
|
Message msg = Message.restoreMessageWithId(INSTANCE, req.mMessageId);
|
||||||
if (msg == null) {
|
if (msg == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1739,33 +1742,7 @@ public class SyncManager extends Service implements Runnable {
|
|||||||
service = startManualSync(mailboxId, SYNC_SERVICE_PART_REQUEST, req);
|
service = startManualSync(mailboxId, SYNC_SERVICE_PART_REQUEST, req);
|
||||||
kick("part request");
|
kick("part request");
|
||||||
} else {
|
} else {
|
||||||
service.addPartRequest(req);
|
service.addRequest(req);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static public PartRequest hasPartRequest(long emailId, String part) {
|
|
||||||
if (INSTANCE == null) return null;
|
|
||||||
Message msg = Message.restoreMessageWithId(INSTANCE, emailId);
|
|
||||||
if (msg == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
long mailboxId = msg.mMailboxKey;
|
|
||||||
AbstractSyncService service = INSTANCE.mServiceMap.get(mailboxId);
|
|
||||||
if (service != null) {
|
|
||||||
return service.hasPartRequest(emailId, part);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
static public void cancelPartRequest(long emailId, String part) {
|
|
||||||
Message msg = Message.restoreMessageWithId(INSTANCE, emailId);
|
|
||||||
if (msg == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
long mailboxId = msg.mMailboxKey;
|
|
||||||
AbstractSyncService service = INSTANCE.mServiceMap.get(mailboxId);
|
|
||||||
if (service != null) {
|
|
||||||
service.cancelPartRequest(emailId, part);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1793,7 +1770,7 @@ public class SyncManager extends Service implements Runnable {
|
|||||||
return PING_STATUS_OK;
|
return PING_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static public AbstractSyncService startManualSync(long mailboxId, int reason, PartRequest req) {
|
static public AbstractSyncService startManualSync(long mailboxId, int reason, Request req) {
|
||||||
if (INSTANCE == null || INSTANCE.mServiceMap == null) return null;
|
if (INSTANCE == null || INSTANCE.mServiceMap == null) return null;
|
||||||
synchronized (sSyncToken) {
|
synchronized (sSyncToken) {
|
||||||
if (INSTANCE.mServiceMap.get(mailboxId) == null) {
|
if (INSTANCE.mServiceMap.get(mailboxId) == null) {
|
||||||
@ -1866,7 +1843,7 @@ public class SyncManager extends Service implements Runnable {
|
|||||||
int exitStatus = svc.mExitStatus;
|
int exitStatus = svc.mExitStatus;
|
||||||
switch (exitStatus) {
|
switch (exitStatus) {
|
||||||
case AbstractSyncService.EXIT_DONE:
|
case AbstractSyncService.EXIT_DONE:
|
||||||
if (!svc.mPartRequests.isEmpty()) {
|
if (!svc.mRequests.isEmpty()) {
|
||||||
// TODO Handle this case
|
// TODO Handle this case
|
||||||
}
|
}
|
||||||
errorMap.remove(mailboxId);
|
errorMap.remove(mailboxId);
|
||||||
|
@ -166,6 +166,14 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
|
|||||||
String text = getValue();
|
String text = getValue();
|
||||||
msg.mText = text;
|
msg.mText = text;
|
||||||
break;
|
break;
|
||||||
|
case Tags.EMAIL_MESSAGE_CLASS:
|
||||||
|
String messageClass = getValue();
|
||||||
|
if (messageClass.equals("IPM.Schedule.Meeting.Request")) {
|
||||||
|
msg.mFlags |= Message.FLAG_MEETING_INVITE;
|
||||||
|
} else if (messageClass.equals("IPM.Schedule.Meeting.Canceled")) {
|
||||||
|
msg.mFlags |= Message.FLAG_MEETING_CANCEL_NOTICE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
skipTag();
|
skipTag();
|
||||||
}
|
}
|
||||||
|
65
src/com/android/exchange/adapter/MeetingResponseParser.java
Normal file
65
src/com/android/exchange/adapter/MeetingResponseParser.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/* Copyright (C) 2010 The Android Open Source Project.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.exchange.adapter;
|
||||||
|
|
||||||
|
import com.android.exchange.EasSyncService;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the result of a MeetingRequest command.
|
||||||
|
*/
|
||||||
|
public class MeetingResponseParser extends Parser {
|
||||||
|
private EasSyncService mService;
|
||||||
|
|
||||||
|
public MeetingResponseParser(InputStream in, EasSyncService service) throws IOException {
|
||||||
|
super(in);
|
||||||
|
mService = service;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parseResult() throws IOException {
|
||||||
|
while (nextTag(Tags.MREQ_RESULT) != END) {
|
||||||
|
if (tag == Tags.MREQ_STATUS) {
|
||||||
|
int status = getValueInt();
|
||||||
|
if (status != 1) {
|
||||||
|
mService.userLog("Error in meeting response: " + status);
|
||||||
|
}
|
||||||
|
} else if (tag == Tags.MREQ_CAL_ID) {
|
||||||
|
mService.userLog("Meeting response calendar id: " + getValue());
|
||||||
|
} else {
|
||||||
|
skipTag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean parse() throws IOException {
|
||||||
|
boolean res = false;
|
||||||
|
if (nextTag(START_DOCUMENT) != Tags.MREQ_MEETING_RESPONSE) {
|
||||||
|
throw new IOException();
|
||||||
|
}
|
||||||
|
while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
|
||||||
|
if (tag == Tags.MREQ_RESULT) {
|
||||||
|
parseResult();
|
||||||
|
} else {
|
||||||
|
skipTag();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -39,6 +39,7 @@ public class Tags {
|
|||||||
public static final int MOVE = 0x05;
|
public static final int MOVE = 0x05;
|
||||||
public static final int GIE = 0x06;
|
public static final int GIE = 0x06;
|
||||||
public static final int FOLDER = 0x07;
|
public static final int FOLDER = 0x07;
|
||||||
|
public static final int MREQ = 0x08;
|
||||||
public static final int TASK = 0x09;
|
public static final int TASK = 0x09;
|
||||||
public static final int CONTACTS2 = 0x0C;
|
public static final int CONTACTS2 = 0x0C;
|
||||||
public static final int PING = 0x0D;
|
public static final int PING = 0x0D;
|
||||||
@ -218,6 +219,17 @@ public class Tags {
|
|||||||
public static final int FOLDER_COUNT = FOLDER_PAGE + 0x17;
|
public static final int FOLDER_COUNT = FOLDER_PAGE + 0x17;
|
||||||
public static final int FOLDER_VERSION = FOLDER_PAGE + 0x18;
|
public static final int FOLDER_VERSION = FOLDER_PAGE + 0x18;
|
||||||
|
|
||||||
|
public static final int MREQ_PAGE = MREQ << PAGE_SHIFT;
|
||||||
|
public static final int MREQ_CAL_ID = MREQ_PAGE + 5;
|
||||||
|
public static final int MREQ_COLLECTION_ID = MREQ_PAGE + 6;
|
||||||
|
public static final int MREQ_MEETING_RESPONSE = MREQ_PAGE + 7;
|
||||||
|
public static final int MREQ_REQ_ID = MREQ_PAGE + 8;
|
||||||
|
public static final int MREQ_REQUEST = MREQ_PAGE + 9;
|
||||||
|
public static final int MREQ_RESULT = MREQ_PAGE + 0xA;
|
||||||
|
public static final int MREQ_STATUS = MREQ_PAGE + 0xB;
|
||||||
|
public static final int MREQ_USER_RESPONSE = MREQ_PAGE + 0xC;
|
||||||
|
public static final int MREQ_VERSION = MREQ_PAGE + 0xD;
|
||||||
|
|
||||||
public static final int EMAIL_PAGE = EMAIL << PAGE_SHIFT;
|
public static final int EMAIL_PAGE = EMAIL << PAGE_SHIFT;
|
||||||
public static final int EMAIL_ATTACHMENT = EMAIL_PAGE + 5;
|
public static final int EMAIL_ATTACHMENT = EMAIL_PAGE + 5;
|
||||||
public static final int EMAIL_ATTACHMENTS = EMAIL_PAGE + 6;
|
public static final int EMAIL_ATTACHMENTS = EMAIL_PAGE + 6;
|
||||||
@ -441,6 +453,8 @@ public class Tags {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
// 0x08 MeetingResponse
|
// 0x08 MeetingResponse
|
||||||
|
"CalId", "CollectionId", "MeetingResponse", "ReqId", "Request",
|
||||||
|
"Result", "Status", "UserResponse", "Version"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// 0x09 Tasks
|
// 0x09 Tasks
|
||||||
|
Loading…
Reference in New Issue
Block a user