Send cancellation email when user-created event is deleted

Bug: 2465496
Change-Id: I49bf9951e816a4500b7622cbca84fb75edfdb76c
diff --git a/res/values/strings.xml b/res/values/strings.xml
index caee97c..c195967 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -634,6 +634,10 @@
          and the title of the meeting (i.e. the title of the meeting becomes part of the subject of
          the message that's sent) -->
     <string name="meeting_tentative">Tentative: <xliff:g id="subject">%s</xliff:g></string>
+    <!-- Message subject for a canceled meeting email.  This is followed by a colon
+         and the title of the meeting (i.e. the title of the meeting becomes part of the subject of
+         the message that's sent) -->
+    <string name="meeting_canceled">Canceled: <xliff:g id="subject">%s</xliff:g></string>
 
 	<!-- Message that appears if the AccountManager cannot create the system Account -->
 	<string name="system_account_create_failed">The AccountManager could not create the Account; please try again.</string>
diff --git a/src/com/android/exchange/adapter/CalendarSyncAdapter.java b/src/com/android/exchange/adapter/CalendarSyncAdapter.java
index 92a7a45..4b97c38 100644
--- a/src/com/android/exchange/adapter/CalendarSyncAdapter.java
+++ b/src/com/android/exchange/adapter/CalendarSyncAdapter.java
@@ -103,6 +103,7 @@
 
     private ArrayList<Long> mDeletedIdList = new ArrayList<Long>();
     private ArrayList<Long> mUpdatedIdList = new ArrayList<Long>();
+    private ArrayList<Long> mSendCancelIdList = new ArrayList<Long>();
 
     private String[] mCalendarIdArgument;
 
@@ -772,6 +773,23 @@
             mOps.add(SyncStateContract.Helpers.newSetOperation(SyncState.CONTENT_URI,
                     mAccountManagerAccount, mMailbox.mSyncKey.getBytes()));
 
+            // We need to send cancellations now, because the Event won't exist after the commit
+            for (long eventId: mSendCancelIdList) {
+                EmailContent.Message msg;
+                try {
+                    msg = CalendarUtilities.createMessageForEventId(mContext, eventId,
+                            EmailContent.Message.FLAG_OUTGOING_MEETING_CANCEL, null,
+                            mAccount);
+                } catch (RemoteException e) {
+                    // Nothing to do here; the Event may no longer exist
+                    continue;
+                }
+                if (msg != null) {
+                    EasOutboxService.sendMessage(mContext, mAccount.mId, msg);
+                }
+            }
+            mSendCancelIdList.clear();
+
             // Execute these all at once...
             mOps.execute();
 
@@ -781,6 +799,13 @@
                 cv.put(Events._SYNC_DIRTY, 0);
                 mContentResolver.update(sEventsUri, cv, DIRTY_IN_CALENDAR,
                         new String[] {Long.toString(mCalendarId)});
+                // Send meeting cancelation notices
+                // Really delete the events...
+                for (long eventId: mDeletedIdList) {
+                    mContentResolver.delete(ContentUris.withAppendedId(sEventsUri, eventId),
+                            null, null);
+                }
+                mDeletedIdList.clear();
             }
         }
 
@@ -1218,7 +1243,11 @@
                         if (entityValues.getAsInteger(Events.DELETED) == 1) {
                             userLog("Deleting event with serverId: ", serverId);
                             s.start(Tags.SYNC_DELETE).data(Tags.SYNC_SERVER_ID, serverId).end();
-                            mDeletedIdList.add(entityValues.getAsLong(Events._ID));
+                            mDeletedIdList.add(eventId);
+                            if (entityValues.getAsString(Events.ORGANIZER)
+                                    .equalsIgnoreCase(mAccount.mEmailAddress)) {
+                                mSendCancelIdList.add(eventId);
+                            }
                             continue;
                         }
                         userLog("Upsync change to event with serverId: " + serverId);
diff --git a/src/com/android/exchange/utility/CalendarUtilities.java b/src/com/android/exchange/utility/CalendarUtilities.java
index 031fdbe..d71c834 100644
--- a/src/com/android/exchange/utility/CalendarUtilities.java
+++ b/src/com/android/exchange/utility/CalendarUtilities.java
@@ -858,7 +858,7 @@
         msg.mTimeStamp = System.currentTimeMillis();
 
         String method;
-        if (messageFlag == EmailContent.Message.FLAG_OUTGOING_MEETING_INVITE) {
+        if ((messageFlag & EmailContent.Message.FLAG_OUTGOING_MEETING_REQUEST_MASK) != 0) {
             method = "REQUEST";
         } else {
             method = "REPLY";
@@ -934,14 +934,18 @@
                 case Message.FLAG_OUTGOING_MEETING_TENTATIVE:
                     titleId = R.string.meeting_tentative;
                     break;
+                case Message.FLAG_OUTGOING_MEETING_CANCEL:
+                    titleId = R.string.meeting_canceled;
+                    break;
             }
             String title = entityValues.getAsString(Events.TITLE);
             if (title == null) {
                 title = "";
             }
             ics.writeTag("SUMMARY", title);
-            msg.mSubject = context.getResources().getString(titleId, title);
-
+            if (titleId != 0) {
+                msg.mSubject = context.getResources().getString(titleId, title);
+            }
             if (method.equals("REQUEST")) {
                 if (entityValues.containsKey(Events.ALL_DAY)) {
                     Integer ade = entityValues.getAsInteger(Events.ALL_DAY);
@@ -1006,7 +1010,7 @@
                         // This shouldn't be possible, but allow for it
                         if (attendeeEmail == null) continue;
 
-                        if (messageFlag == Message.FLAG_OUTGOING_MEETING_INVITE) {
+                        if ((messageFlag & Message.FLAG_OUTGOING_MEETING_REQUEST_MASK) != 0) {
                             String icalTag = ICALENDAR_ATTENDEE_INVITE;
                             if (attendeeName != null) {
                                 icalTag += ";CN=" + attendeeName;