EAS implementation of "move to folder"
* Handle errors cases appropriately Change-Id: I16060cc5c4fc648c299a2fa8f9f57d9aa5c37f56
This commit is contained in:
parent
486761169d
commit
d694a20849
@ -32,6 +32,7 @@ import com.android.email.provider.EmailContent.HostAuth;
|
||||
import com.android.email.provider.EmailContent.Mailbox;
|
||||
import com.android.email.provider.EmailContent.MailboxColumns;
|
||||
import com.android.email.provider.EmailContent.Message;
|
||||
import com.android.email.provider.EmailContent.MessageColumns;
|
||||
import com.android.email.service.EmailServiceConstants;
|
||||
import com.android.email.service.EmailServiceProxy;
|
||||
import com.android.email.service.EmailServiceStatus;
|
||||
@ -43,6 +44,7 @@ import com.android.exchange.adapter.EmailSyncAdapter;
|
||||
import com.android.exchange.adapter.FolderSyncParser;
|
||||
import com.android.exchange.adapter.GalParser;
|
||||
import com.android.exchange.adapter.MeetingResponseParser;
|
||||
import com.android.exchange.adapter.MoveItemsParser;
|
||||
import com.android.exchange.adapter.PingParser;
|
||||
import com.android.exchange.adapter.ProvisionParser;
|
||||
import com.android.exchange.adapter.Serializer;
|
||||
@ -1061,6 +1063,69 @@ public class EasSyncService extends AbstractSyncService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to a move request. The MessageMoveRequest is basically our
|
||||
* wrapper for the MoveItems service call
|
||||
* @param req the request (message id and "to" mailbox id)
|
||||
* @throws IOException
|
||||
*/
|
||||
protected void messageMoveRequest(MessageMoveRequest req) throws IOException {
|
||||
// Retrieve the message and mailbox; punt if either are null
|
||||
Message msg = Message.restoreMessageWithId(mContext, req.mMessageId);
|
||||
if (msg == null) return;
|
||||
Cursor c = mContentResolver.query(ContentUris.withAppendedId(Message.UPDATED_CONTENT_URI,
|
||||
msg.mId), new String[] {MessageColumns.MAILBOX_KEY}, null, null, null);
|
||||
Mailbox srcMailbox = null;
|
||||
try {
|
||||
if (!c.moveToNext()) return;
|
||||
srcMailbox = Mailbox.restoreMailboxWithId(mContext, c.getLong(0));
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
if (srcMailbox == null) return;
|
||||
Mailbox dstMailbox = Mailbox.restoreMailboxWithId(mContext, req.mMailboxId);
|
||||
if (dstMailbox == null) return;
|
||||
Serializer s = new Serializer();
|
||||
s.start(Tags.MOVE_MOVE_ITEMS).start(Tags.MOVE_MOVE);
|
||||
s.data(Tags.MOVE_SRCMSGID, msg.mServerId);
|
||||
s.data(Tags.MOVE_SRCFLDID, srcMailbox.mServerId);
|
||||
s.data(Tags.MOVE_DSTFLDID, dstMailbox.mServerId);
|
||||
s.end().end().done();
|
||||
HttpResponse res = sendHttpClientPost("MoveItems", 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) {
|
||||
MoveItemsParser p = new MoveItemsParser(is, this);
|
||||
p.parse();
|
||||
int statusCode = p.getStatusCode();
|
||||
if (statusCode == MoveItemsParser.STATUS_CODE_REVERT) {
|
||||
// Restore the old mailbox id
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(MessageColumns.MAILBOX_KEY, srcMailbox.mServerId);
|
||||
mContentResolver.update(ContentUris.withAppendedId(
|
||||
Message.CONTENT_URI, req.mMessageId), cv, null, null);
|
||||
}
|
||||
if (statusCode == MoveItemsParser.STATUS_CODE_SUCCESS ||
|
||||
statusCode == MoveItemsParser.STATUS_CODE_REVERT) {
|
||||
// If we revert or if we succeeded, we no longer need the update information
|
||||
mContentResolver.delete(ContentUris.withAppendedId(
|
||||
Message.UPDATED_CONTENT_URI, req.mMessageId), null, null);
|
||||
} else {
|
||||
// In this case, we're retrying, so do nothing. The request will be handled
|
||||
// next sync
|
||||
}
|
||||
}
|
||||
} else if (isAuthError(status)) {
|
||||
throw new EasAuthenticationException();
|
||||
} else {
|
||||
userLog("Move items request failed, code: " + status);
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Responds to a meeting request. The MeetingResponseRequest is basically our
|
||||
* wrapper for the meetingResponse service call
|
||||
@ -2059,6 +2124,8 @@ public class EasSyncService extends AbstractSyncService {
|
||||
loadAttachment((PartRequest)req);
|
||||
} else if (req instanceof MeetingResponseRequest) {
|
||||
sendMeetingResponse((MeetingResponseRequest)req);
|
||||
} else if (req instanceof MessageMoveRequest) {
|
||||
messageMoveRequest((MessageMoveRequest)req);
|
||||
}
|
||||
|
||||
// If there's an exception handling the request, we'll throw it
|
||||
|
29
src/com/android/exchange/MessageMoveRequest.java
Normal file
29
src/com/android/exchange/MessageMoveRequest.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;
|
||||
|
||||
/**
|
||||
* MessageMoveRequest is the EAS wrapper for requesting a "move to folder"
|
||||
*/
|
||||
public class MessageMoveRequest extends Request {
|
||||
public final long mMailboxId;
|
||||
|
||||
public MessageMoveRequest(long messageId, long mailboxId) {
|
||||
mMessageId = messageId;
|
||||
mMailboxId = mailboxId;
|
||||
}
|
||||
}
|
@ -429,6 +429,7 @@ public class SyncManager extends Service implements Runnable {
|
||||
}
|
||||
|
||||
public void moveMessage(long messageId, long mailboxId) throws RemoteException {
|
||||
sendMessageRequest(new MessageMoveRequest(messageId, mailboxId));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -35,6 +35,7 @@ import com.android.email.provider.EmailContent.SyncColumns;
|
||||
import com.android.email.service.MailService;
|
||||
import com.android.exchange.Eas;
|
||||
import com.android.exchange.EasSyncService;
|
||||
import com.android.exchange.MessageMoveRequest;
|
||||
import com.android.exchange.utility.CalendarUtilities;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
@ -775,9 +776,22 @@ public class EmailSyncAdapter extends AbstractSyncAdapter {
|
||||
boolean flagChange = false;
|
||||
boolean readChange = false;
|
||||
|
||||
int flag = 0;
|
||||
long mailbox = currentCursor.getLong(UPDATES_MAILBOX_KEY_COLUMN);
|
||||
if (mailbox != c.getLong(Message.LIST_MAILBOX_KEY_COLUMN)) {
|
||||
// The message has moved to another mailbox; add a request for this
|
||||
// Note: The Sync command doesn't handle moving messages, so we need
|
||||
// to handle this as a "request" (similar to meeting response and
|
||||
// attachment load)
|
||||
mService.addRequest(new MessageMoveRequest(id, mailbox));
|
||||
// Regardless of other changes that might be made, we don't want to indicate
|
||||
// that this message has been updated until the move request has been
|
||||
// handled (without this, a crash between the flag upsync and the move
|
||||
// would cause the move to be lost)
|
||||
mUpdatedIdList.remove(id);
|
||||
}
|
||||
|
||||
// We can only send flag changes to the server in 12.0 or later
|
||||
int flag = 0;
|
||||
if (mService.mProtocolVersionDouble >= Eas.SUPPORTED_PROTOCOL_EX2007_DOUBLE) {
|
||||
flag = currentCursor.getInt(UPDATES_FLAG_COLUMN);
|
||||
if (flag != c.getInt(Message.LIST_FAVORITE_COLUMN)) {
|
||||
|
107
src/com/android/exchange/adapter/MoveItemsParser.java
Normal file
107
src/com/android/exchange/adapter/MoveItemsParser.java
Normal file
@ -0,0 +1,107 @@
|
||||
/* 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 MoveItems command.
|
||||
*/
|
||||
public class MoveItemsParser extends Parser {
|
||||
private final EasSyncService mService;
|
||||
private int mStatusCode = 0;
|
||||
|
||||
// These are the EAS status codes for MoveItems
|
||||
private static final int STATUS_NO_SOURCE_FOLDER = 1;
|
||||
private static final int STATUS_NO_DESTINATION_FOLDER = 2;
|
||||
private static final int STATUS_SUCCESS = 3;
|
||||
private static final int STATUS_SOURCE_DESTINATION_SAME = 4;
|
||||
private static final int STATUS_INTERNAL_ERROR = 5;
|
||||
private static final int STATUS_ALREADY_EXISTS = 6;
|
||||
private static final int STATUS_LOCKED = 7;
|
||||
|
||||
// These are the status values we return to callers
|
||||
public static final int STATUS_CODE_SUCCESS = 1;
|
||||
public static final int STATUS_CODE_REVERT = 2;
|
||||
public static final int STATUS_CODE_RETRY = 3;
|
||||
|
||||
public MoveItemsParser(InputStream in, EasSyncService service) throws IOException {
|
||||
super(in);
|
||||
mService = service;
|
||||
}
|
||||
|
||||
public int getStatusCode() {
|
||||
return mStatusCode;
|
||||
}
|
||||
|
||||
public void parseResponse() throws IOException {
|
||||
while (nextTag(Tags.MOVE_RESPONSE) != END) {
|
||||
if (tag == Tags.MOVE_STATUS) {
|
||||
int status = getValueInt();
|
||||
// Convert the EAS status code with our external codes
|
||||
switch(status) {
|
||||
case STATUS_SUCCESS:
|
||||
case STATUS_SOURCE_DESTINATION_SAME:
|
||||
case STATUS_ALREADY_EXISTS:
|
||||
// Same destination and already exists are ok with us; we'll continue as
|
||||
// if the move succeeded
|
||||
mStatusCode = STATUS_CODE_SUCCESS;
|
||||
break;
|
||||
case STATUS_LOCKED:
|
||||
// This sounds like a transient error, so we can safely retry
|
||||
mStatusCode = STATUS_CODE_RETRY;
|
||||
break;
|
||||
case STATUS_NO_SOURCE_FOLDER:
|
||||
case STATUS_NO_DESTINATION_FOLDER:
|
||||
case STATUS_INTERNAL_ERROR:
|
||||
default:
|
||||
// These are non-recoverable, so we'll revert the message to its original
|
||||
// mailbox. If there's an unknown response, revert
|
||||
mStatusCode = STATUS_CODE_REVERT;
|
||||
break;
|
||||
}
|
||||
if (status != STATUS_SUCCESS) {
|
||||
// There's not much to be done if this fails
|
||||
mService.userLog("Error in MoveItems: " + status);
|
||||
}
|
||||
} else if (tag == Tags.MOVE_DSTMSGID || tag == Tags.MOVE_SRCMSGID) {
|
||||
mService.userLog("Moved message id is now: " + getValue());
|
||||
} else {
|
||||
skipTag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parse() throws IOException {
|
||||
boolean res = false;
|
||||
if (nextTag(START_DOCUMENT) != Tags.MOVE_MOVE_ITEMS) {
|
||||
throw new IOException();
|
||||
}
|
||||
while (nextTag(START_DOCUMENT) != END_DOCUMENT) {
|
||||
if (tag == Tags.MOVE_RESPONSE) {
|
||||
parseResponse();
|
||||
} else {
|
||||
skipTag();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user