1/*
2 *  Copyright (C) 2008-2009 Marc Blank
3 * Licensed to The Android Open Source Project.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.exchange;
19
20import android.content.BroadcastReceiver;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.database.Cursor;
25import android.util.Log;
26
27import com.android.emailcommon.provider.EmailContent.Message;
28import com.android.emailcommon.provider.EmailContent.MessageColumns;
29import com.android.emailcommon.provider.ProviderUnavailableException;
30
31import java.util.ArrayList;
32
33/**
34 * EmailSyncAlarmReceiver (USAR) is used by the SyncManager to start up-syncs of user-modified data
35 * back to the Exchange server.
36 *
37 * Here's how this works for Email, for example:
38 *
39 * 1) User modifies or deletes an email from the UI.
40 * 2) SyncManager, which has a ContentObserver watching the Message class, is alerted to a change
41 * 3) SyncManager sets an alarm (to be received by USAR) for a few seconds in the
42 * future (currently 15), the delay preventing excess syncing (think of it as a debounce mechanism).
43 * 4) ESAR Receiver's onReceive method is called
44 * 5) ESAR goes through all change and deletion records and compiles a list of mailboxes which have
45 * changes to be uploaded.
46 * 6) ESAR calls SyncManager to start syncs of those mailboxes
47 *
48 * If EmailProvider isn't available, the upsyncs will happen the next time ExchangeService starts
49 *
50 */
51public class EmailSyncAlarmReceiver extends BroadcastReceiver {
52    final String[] MAILBOX_DATA_PROJECTION = {MessageColumns.MAILBOX_KEY};
53
54    @Override
55    public void onReceive(final Context context, Intent intent) {
56        new Thread(new Runnable() {
57            public void run() {
58                handleReceive(context);
59            }
60        }).start();
61    }
62
63    private void handleReceive(Context context) {
64        ArrayList<Long> mailboxesToNotify = new ArrayList<Long>();
65        ContentResolver cr = context.getContentResolver();
66        int messageCount = 0;
67
68        // Get a selector for EAS accounts (we don't want to sync on changes to POP/IMAP messages)
69        String selector = ExchangeService.getEasAccountSelector();
70
71        try {
72            // Find all of the deletions
73            Cursor c = cr.query(Message.DELETED_CONTENT_URI, MAILBOX_DATA_PROJECTION, selector,
74                   null, null);
75            if (c == null) throw new ProviderUnavailableException();
76            try {
77                // Keep track of which mailboxes to notify; we'll only notify each one once
78                while (c.moveToNext()) {
79                    messageCount++;
80                    long mailboxId = c.getLong(0);
81                    if (!mailboxesToNotify.contains(mailboxId)) {
82                        mailboxesToNotify.add(mailboxId);
83                    }
84                }
85            } finally {
86                c.close();
87            }
88
89            // Now, find changed messages
90            c = cr.query(Message.UPDATED_CONTENT_URI, MAILBOX_DATA_PROJECTION, selector,
91                    null, null);
92            if (c == null) throw new ProviderUnavailableException();
93            try {
94                // Keep track of which mailboxes to notify; we'll only notify each one once
95                while (c.moveToNext()) {
96                    messageCount++;
97                    long mailboxId = c.getLong(0);
98                    if (!mailboxesToNotify.contains(mailboxId)) {
99                        mailboxesToNotify.add(mailboxId);
100                    }
101                }
102            } finally {
103                c.close();
104            }
105
106            // Request service from the mailbox
107            for (Long mailboxId: mailboxesToNotify) {
108                ExchangeService.serviceRequest(mailboxId, ExchangeService.SYNC_UPSYNC);
109            }
110        } catch (ProviderUnavailableException e) {
111            Log.e("EmailSyncAlarmReceiver", "EmailProvider unavailable; aborting alarm receiver");
112        }
113    }
114}
115