1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.datamodel.action;
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentValues;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Intent;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.database.Cursor;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.ConnectivityManager;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Parcel;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Parcelable;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.ServiceState;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.BugleDatabaseOperations;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DataModel;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DatabaseHelper;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DatabaseHelper.MessageColumns;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.DatabaseWrapper;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.MessagingContentProvider;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.MessageData;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.ParticipantData;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.sms.MmsUtils;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.BugleGservices;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.BugleGservicesKeys;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.BuglePrefs;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.BuglePrefsKeys;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.ConnectivityUtil.ConnectivityListener;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.LogUtil;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.OsUtil;
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.PhoneUtils;
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.HashSet;
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Set;
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Action used to lookup any messages in the pending send/download state and either fail them or
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * retry their action. This action only initiates one retry at a time - further retries should be
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * triggered by successful sending of a message, network status change or exponential backoff timer.
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class ProcessPendingMessagesAction extends Action implements Parcelable {
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int PENDING_INTENT_REQUEST_CODE = 101;
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void processFirstPendingMessage() {
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Clear any pending alarms or connectivity events
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        unregister();
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Clear retry count
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        setRetry(0);
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Start action
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        action.start();
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static void scheduleProcessPendingMessagesAction(final boolean failed,
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Action processingAction) {
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LogUtil.i(TAG, "ProcessPendingMessagesAction: Scheduling pending messages"
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                + (failed ? "(message failed)" : ""));
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Can safely clear any pending alarms or connectivity events as either an action
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // is currently running or we will run now or register if pending actions possible.
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        unregister();
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean isDefaultSmsApp = PhoneUtils.getDefault().isDefaultSmsApp();
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean scheduleAlarm = false;
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // If message succeeded and if Bugle is default SMS app just carry on with next message
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!failed && isDefaultSmsApp) {
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Clear retry attempt count as something just succeeded
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            setRetry(0);
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Lookup and queue next message for immediate processing by background worker
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            //  iff there are no pending messages this will do nothing and return true.
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (action.queueActions(processingAction)) {
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (processingAction.hasBackgroundActions()) {
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.v(TAG, "ProcessPendingMessagesAction: Action queued");
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    } else {
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        LogUtil.v(TAG, "ProcessPendingMessagesAction: No actions to queue");
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Have queued next action if needed, nothing more to do
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return;
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // In case of error queuing schedule a retry
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            scheduleAlarm = true;
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.w(TAG, "ProcessPendingMessagesAction: Action failed to queue; retrying");
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (getHavePendingMessages() || scheduleAlarm) {
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Still have a pending message that needs to be queued for processing
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ConnectivityListener listener = new ConnectivityListener() {
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                @Override
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                public void onConnectivityStateChanged(final Context context, final Intent intent) {
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final int networkType =
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            MmsUtils.getConnectivityEventNetworkType(context, intent);
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (networkType != ConnectivityManager.TYPE_MOBILE) {
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        return;
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final boolean isConnected = !intent.getBooleanExtra(
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // TODO: Should we check in more detail?
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (isConnected) {
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        onConnected();
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                @Override
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                public void onPhoneStateChanged(final Context context, final int serviceState) {
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (serviceState == ServiceState.STATE_IN_SERVICE) {
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        onConnected();
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                private void onConnected() {
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    LogUtil.i(TAG, "ProcessPendingMessagesAction: Now connected; starting action");
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Clear any pending alarms or connectivity events but leave attempt count alone
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    unregister();
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Start action
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    action.start();
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            };
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Read and increment attempt number from shared prefs
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int retryAttempt = getNextRetry();
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            register(listener, retryAttempt);
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // No more pending messages (presumably the message that failed has expired) or it
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // may be possible that a send and a download are already in process.
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Clear retry attempt count.
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // TODO Might be premature if send and download in process...
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            //  but worst case means we try to send a bit more often.
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            setRetry(0);
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "ProcessPendingMessagesAction: No more pending messages");
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void register(final ConnectivityListener listener, final int retryAttempt) {
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int retryNumber = retryAttempt;
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Register to be notified about connectivity changes
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        DataModel.get().getConnectivityUtil().register(listener);
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long initialBackoffMs = BugleGservices.get().getLong(
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS,
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS_DEFAULT);
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long maxDelayMs = BugleGservices.get().getLong(
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                BugleGservicesKeys.MAX_MESSAGE_RESEND_DELAY_MS,
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                BugleGservicesKeys.MAX_MESSAGE_RESEND_DELAY_MS_DEFAULT);
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        long delayMs;
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        long nextDelayMs = initialBackoffMs;
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        do {
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            delayMs = nextDelayMs;
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            retryNumber--;
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            nextDelayMs = delayMs * 2;
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        while (retryNumber > 0 && nextDelayMs < maxDelayMs);
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        LogUtil.i(TAG, "ProcessPendingMessagesAction: Registering for retry #" + retryAttempt
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                + " in " + delayMs + " ms");
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        action.schedule(PENDING_INTENT_REQUEST_CODE, delayMs);
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void unregister() {
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Clear any pending alarms or connectivity events
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        DataModel.get().getConnectivityUtil().unregister();
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        action.schedule(PENDING_INTENT_REQUEST_CODE, Long.MAX_VALUE);
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.v(TAG, "ProcessPendingMessagesAction: Unregistering for connectivity changed "
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + "events and clearing scheduled alarm");
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static void setRetry(final int retryAttempt) {
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final BuglePrefs prefs = Factory.get().getApplicationPrefs();
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        prefs.putInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, retryAttempt);
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static int getNextRetry() {
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final BuglePrefs prefs = Factory.get().getApplicationPrefs();
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int retryAttempt =
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                prefs.getInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, 0) + 1;
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        prefs.putInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, retryAttempt);
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return retryAttempt;
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ProcessPendingMessagesAction() {
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Read from the DB and determine if there are any messages we should process
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if we have pending messages
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static boolean getHavePendingMessages() {
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final DatabaseWrapper db = DataModel.get().getDatabase();
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long now = System.currentTimeMillis();
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String toSendMessageId = findNextMessageToSend(db, now);
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (toSendMessageId != null) {
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final String toDownloadMessageId = findNextMessageToDownload(db, now);
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (toDownloadMessageId != null) {
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return true;
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Messages may be in the process of sending/downloading even when there are no pending
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // messages...
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return false;
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Queue any pending actions
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @param actionState
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * @return true if action queued (or no actions to queue) else false
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private boolean queueActions(final Action processingAction) {
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final DatabaseWrapper db = DataModel.get().getDatabase();
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final long now = System.currentTimeMillis();
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean succeeded = true;
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Will queue no more than one message to send plus one message to download
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // This keeps outgoing messages "in order" but allow downloads to happen even if sending
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        //  gets blocked until messages time out.  Manual resend bumps messages to head of queue.
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String toSendMessageId = findNextMessageToSend(db, now);
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final String toDownloadMessageId = findNextMessageToDownload(db, now);
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (toSendMessageId != null) {
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message " + toSendMessageId
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + " for sending");
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // This could queue nothing
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!SendMessageAction.queueForSendInBackground(toSendMessageId, processingAction)) {
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        + toSendMessageId + " for sending");
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                succeeded = false;
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (toDownloadMessageId != null) {
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message " + toDownloadMessageId
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + " for download");
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // This could queue nothing
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!DownloadMmsAction.queueMmsForDownloadInBackground(toDownloadMessageId,
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    processingAction)) {
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        + toDownloadMessageId + " for download");
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                succeeded = false;
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (toSendMessageId == null && toDownloadMessageId == null) {
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.d(TAG, "ProcessPendingMessagesAction: No messages to send or download");
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return succeeded;
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected Object executeAction() {
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // If triggered by alarm will not have unregistered yet
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        unregister();
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (PhoneUtils.getDefault().isDefaultSmsApp()) {
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            queueActions(this);
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                LogUtil.v(TAG, "ProcessPendingMessagesAction: Not default SMS app; rescheduling");
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            scheduleProcessPendingMessagesAction(true, this);
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static String findNextMessageToSend(final DatabaseWrapper db, final long now) {
297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String toSendMessageId = null;
298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        db.beginTransaction();
299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor sending = null;
300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor cursor = null;
301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int sendingCnt = 0;
302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int pendingCnt = 0;
303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int failedCnt = 0;
304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // First check to see if we have any messages already sending
306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            sending = db.query(DatabaseHelper.MESSAGES_TABLE,
307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    MessageData.getProjection(),
308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DatabaseHelper.MessageColumns.STATUS + " IN (?, ?)",
309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new String[]{Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_SENDING),
310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                           Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_RESENDING)},
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null,
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null,
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DatabaseHelper.MessageColumns.RECEIVED_TIMESTAMP + " ASC");
314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final boolean messageCurrentlySending = sending.moveToNext();
315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            sendingCnt = sending.getCount();
316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Look for messages we could send
317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ContentValues values = new ContentValues();
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            values.put(DatabaseHelper.MessageColumns.STATUS,
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    MessageData.BUGLE_STATUS_OUTGOING_FAILED);
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            cursor = db.query(DatabaseHelper.MESSAGES_TABLE,
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    MessageData.getProjection(),
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DatabaseHelper.MessageColumns.STATUS + " IN ("
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            + MessageData.BUGLE_STATUS_OUTGOING_YET_TO_SEND + ","
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            + MessageData.BUGLE_STATUS_OUTGOING_AWAITING_RETRY + ")",
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null,
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null,
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null,
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DatabaseHelper.MessageColumns.RECEIVED_TIMESTAMP + " ASC");
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            pendingCnt = cursor.getCount();
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            while (cursor.moveToNext()) {
332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final MessageData message = new MessageData();
333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                message.bind(cursor);
334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (message.getInResendWindow(now)) {
335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // If no messages currently sending
336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (!messageCurrentlySending) {
337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // Resend this message
338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        toSendMessageId = message.getMessageId();
339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // Before queuing the message for resending, check if the message's self is
340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        // active. If not, switch back to the system's default subscription.
341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        if (OsUtil.isAtLeastL_MR1()) {
342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            final ParticipantData messageSelf = BugleDatabaseOperations
343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    .getExistingParticipant(db, message.getSelfId());
344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            if (messageSelf == null || !messageSelf.isActiveSubscription()) {
345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                final ParticipantData defaultSelf = BugleDatabaseOperations
346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                        .getOrCreateSelf(db, PhoneUtils.getDefault()
347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                                .getDefaultSmsSubscriptionId());
348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                if (defaultSelf != null) {
349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    message.bindSelfId(defaultSelf.getId());
350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    final ContentValues selfValues = new ContentValues();
351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    selfValues.put(MessageColumns.SELF_PARTICIPANT_ID,
352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                            defaultSelf.getId());
353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    BugleDatabaseOperations.updateMessageRow(db,
354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                            message.getMessageId(), selfValues);
355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    MessagingContentProvider.notifyMessagesChanged(
356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                            message.getConversationId());
357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                }
358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            }
359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } else {
363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    failedCnt++;
364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Mark message as failed
366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    BugleDatabaseOperations.updateMessageRow(db, message.getMessageId(), values);
367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    MessagingContentProvider.notifyMessagesChanged(message.getConversationId());
368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.setTransactionSuccessful();
371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.endTransaction();
373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                cursor.close();
375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (sending != null) {
377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                sending.close();
378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.d(TAG, "ProcessPendingMessagesAction: "
383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + sendingCnt + " messages already sending, "
384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + pendingCnt + " messages to send, "
385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + failedCnt + " failed messages");
386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return toSendMessageId;
389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static String findNextMessageToDownload(final DatabaseWrapper db, final long now) {
392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        String toDownloadMessageId = null;
393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        db.beginTransaction();
394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Cursor cursor = null;
395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int downloadingCnt = 0;
396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int pendingCnt = 0;
397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        try {
398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // First check if we have any messages already downloading
399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            downloadingCnt = (int) db.queryNumEntries(DatabaseHelper.MESSAGES_TABLE,
400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DatabaseHelper.MessageColumns.STATUS + " IN (?, ?)",
401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new String[] {
402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        Integer.toString(MessageData.BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING),
403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        Integer.toString(MessageData.BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING)
404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    });
405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // TODO: This query is not actually needed if downloadingCnt == 0.
407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            cursor = db.query(DatabaseHelper.MESSAGES_TABLE,
408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    MessageData.getProjection(),
409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DatabaseHelper.MessageColumns.STATUS + " =? OR "
410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            + DatabaseHelper.MessageColumns.STATUS + " =?",
411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    new String[]{
412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            Integer.toString(
413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    MessageData.BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD),
414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            Integer.toString(
415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    MessageData.BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD)
416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    },
417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null,
418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null,
419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    DatabaseHelper.MessageColumns.RECEIVED_TIMESTAMP + " ASC");
420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            pendingCnt = cursor.getCount();
422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // If no messages are currently downloading and there is a download pending,
424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // queue the download of the oldest pending message.
425d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (downloadingCnt == 0 && cursor.moveToNext()) {
426d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Always start the next pending message. We will check if a download has
427d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // expired in DownloadMmsAction and mark message failed there.
428d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final MessageData message = new MessageData();
429d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                message.bind(cursor);
430d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                toDownloadMessageId = message.getMessageId();
431d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
432d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.setTransactionSuccessful();
433d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } finally {
434d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            db.endTransaction();
435d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (cursor != null) {
436d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                cursor.close();
437d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
438d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
439d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
440d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
441d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            LogUtil.d(TAG, "ProcessPendingMessagesAction: "
442d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + downloadingCnt + " messages already downloading, "
443d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    + pendingCnt + " messages to download");
444d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
445d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
446d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return toDownloadMessageId;
447d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
448d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
449d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ProcessPendingMessagesAction(final Parcel in) {
450d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        super(in);
451d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
452d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
453d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public static final Parcelable.Creator<ProcessPendingMessagesAction> CREATOR
454d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            = new Parcelable.Creator<ProcessPendingMessagesAction>() {
455d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
456d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public ProcessPendingMessagesAction createFromParcel(final Parcel in) {
457d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new ProcessPendingMessagesAction(in);
458d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
459d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
460d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        @Override
461d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public ProcessPendingMessagesAction[] newArray(final int size) {
462d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new ProcessPendingMessagesAction[size];
463d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
464d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
465d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
466d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
467d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void writeToParcel(final Parcel parcel, final int flags) {
468d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        writeActionToParcel(parcel, flags);
469d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
470d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
471