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