|
|
|
@@ -17,76 +17,83 @@
|
|
|
|
|
package com.android.messaging.datamodel.action;
|
|
|
|
|
|
|
|
|
|
import android.content.ContentValues;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.Intent;
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.net.ConnectivityManager;
|
|
|
|
|
import android.os.Parcel;
|
|
|
|
|
import android.os.Parcelable;
|
|
|
|
|
import android.telephony.ServiceState;
|
|
|
|
|
import android.telephony.SubscriptionInfo;
|
|
|
|
|
|
|
|
|
|
import com.android.messaging.Factory;
|
|
|
|
|
import com.android.messaging.datamodel.BugleDatabaseOperations;
|
|
|
|
|
import com.android.messaging.datamodel.DataModel;
|
|
|
|
|
import com.android.messaging.datamodel.DataModelImpl;
|
|
|
|
|
import com.android.messaging.datamodel.DatabaseHelper;
|
|
|
|
|
import com.android.messaging.datamodel.DatabaseHelper.MessageColumns;
|
|
|
|
|
import com.android.messaging.datamodel.DatabaseHelper.ParticipantColumns;
|
|
|
|
|
import com.android.messaging.datamodel.DatabaseWrapper;
|
|
|
|
|
import com.android.messaging.datamodel.MessagingContentProvider;
|
|
|
|
|
import com.android.messaging.datamodel.data.MessageData;
|
|
|
|
|
import com.android.messaging.datamodel.data.ParticipantData;
|
|
|
|
|
import com.android.messaging.sms.MmsUtils;
|
|
|
|
|
import com.android.messaging.util.BugleGservices;
|
|
|
|
|
import com.android.messaging.util.BugleGservicesKeys;
|
|
|
|
|
import com.android.messaging.util.BuglePrefs;
|
|
|
|
|
import com.android.messaging.util.BuglePrefsKeys;
|
|
|
|
|
import com.android.messaging.util.ConnectivityUtil;
|
|
|
|
|
import com.android.messaging.util.ConnectivityUtil.ConnectivityListener;
|
|
|
|
|
import com.android.messaging.util.LogUtil;
|
|
|
|
|
import com.android.messaging.util.OsUtil;
|
|
|
|
|
import com.android.messaging.util.PhoneUtils;
|
|
|
|
|
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Action used to lookup any messages in the pending send/download state and either fail them or
|
|
|
|
|
* retry their action. This action only initiates one retry at a time - further retries should be
|
|
|
|
|
* triggered by successful sending of a message, network status change or exponential backoff timer.
|
|
|
|
|
* retry their action based on subscriptions. This action only initiates one retry at a time for
|
|
|
|
|
* both sending/downloading. Further retries should be triggered by successful sending/downloading
|
|
|
|
|
* of a message, network status change or exponential backoff timer.
|
|
|
|
|
*/
|
|
|
|
|
public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|
|
|
|
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
|
|
|
|
|
private static final int PENDING_INTENT_REQUEST_CODE = 101;
|
|
|
|
|
// PENDING_INTENT_BASE_REQUEST_CODE + subId(-1 for pre-L_MR1) is used per subscription uniquely.
|
|
|
|
|
private static final int PENDING_INTENT_BASE_REQUEST_CODE = 103;
|
|
|
|
|
|
|
|
|
|
private static final String KEY_SUB_ID = "sub_id";
|
|
|
|
|
|
|
|
|
|
public static void processFirstPendingMessage() {
|
|
|
|
|
// Clear any pending alarms or connectivity events
|
|
|
|
|
unregister();
|
|
|
|
|
// Clear retry count
|
|
|
|
|
setRetry(0);
|
|
|
|
|
|
|
|
|
|
// Start action
|
|
|
|
|
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
|
|
|
|
action.start();
|
|
|
|
|
PhoneUtils.forEachActiveSubscription(new PhoneUtils.SubscriptionRunnable() {
|
|
|
|
|
@Override
|
|
|
|
|
public void runForSubscription(final int subId) {
|
|
|
|
|
// Clear any pending alarms or connectivity events
|
|
|
|
|
unregister(subId);
|
|
|
|
|
// Clear retry count
|
|
|
|
|
setRetry(0, subId);
|
|
|
|
|
// Start action
|
|
|
|
|
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
|
|
|
|
action.actionParameters.putInt(KEY_SUB_ID, subId);
|
|
|
|
|
action.start();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void scheduleProcessPendingMessagesAction(final boolean failed,
|
|
|
|
|
final Action processingAction) {
|
|
|
|
|
final int subId = processingAction.actionParameters
|
|
|
|
|
.getInt(KEY_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID);
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Scheduling pending messages"
|
|
|
|
|
+ (failed ? "(message failed)" : ""));
|
|
|
|
|
+ (failed ? "(message failed)" : "") + " for subId " + subId);
|
|
|
|
|
// Can safely clear any pending alarms or connectivity events as either an action
|
|
|
|
|
// is currently running or we will run now or register if pending actions possible.
|
|
|
|
|
unregister();
|
|
|
|
|
unregister(subId);
|
|
|
|
|
|
|
|
|
|
final boolean isDefaultSmsApp = PhoneUtils.getDefault().isDefaultSmsApp();
|
|
|
|
|
boolean scheduleAlarm = false;
|
|
|
|
|
// If message succeeded and if Bugle is default SMS app just carry on with next message
|
|
|
|
|
if (!failed && isDefaultSmsApp) {
|
|
|
|
|
// Clear retry attempt count as something just succeeded
|
|
|
|
|
setRetry(0);
|
|
|
|
|
setRetry(0, subId);
|
|
|
|
|
|
|
|
|
|
// Lookup and queue next message for immediate processing by background worker
|
|
|
|
|
// iff there are no pending messages this will do nothing and return true.
|
|
|
|
|
// Lookup and queue next message for each sending/downloading for immediate processing
|
|
|
|
|
// by background worker. If there are no pending messages, this will do nothing and
|
|
|
|
|
// return true.
|
|
|
|
|
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
|
|
|
|
if (action.queueActions(processingAction)) {
|
|
|
|
|
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
|
|
|
|
@@ -103,66 +110,53 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|
|
|
|
scheduleAlarm = true;
|
|
|
|
|
LogUtil.w(TAG, "ProcessPendingMessagesAction: Action failed to queue; retrying");
|
|
|
|
|
}
|
|
|
|
|
if (getHavePendingMessages() || scheduleAlarm) {
|
|
|
|
|
if (getHavePendingMessages(subId) || scheduleAlarm) {
|
|
|
|
|
// Still have a pending message that needs to be queued for processing
|
|
|
|
|
final ConnectivityListener listener = new ConnectivityListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onConnectivityStateChanged(final Context context, final Intent intent) {
|
|
|
|
|
final int networkType =
|
|
|
|
|
MmsUtils.getConnectivityEventNetworkType(context, intent);
|
|
|
|
|
if (networkType != ConnectivityManager.TYPE_MOBILE) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
final boolean isConnected = !intent.getBooleanExtra(
|
|
|
|
|
ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
|
|
|
|
|
// TODO: Should we check in more detail?
|
|
|
|
|
if (isConnected) {
|
|
|
|
|
onConnected();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onPhoneStateChanged(final Context context, final int serviceState) {
|
|
|
|
|
public void onPhoneStateChanged(final int serviceState) {
|
|
|
|
|
if (serviceState == ServiceState.STATE_IN_SERVICE) {
|
|
|
|
|
onConnected();
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Now connected for subId "
|
|
|
|
|
+ subId + ", starting action");
|
|
|
|
|
|
|
|
|
|
// Clear any pending alarms or connectivity events but leave attempt count
|
|
|
|
|
// alone
|
|
|
|
|
unregister(subId);
|
|
|
|
|
|
|
|
|
|
// Start action
|
|
|
|
|
final ProcessPendingMessagesAction action =
|
|
|
|
|
new ProcessPendingMessagesAction();
|
|
|
|
|
action.actionParameters.putInt(KEY_SUB_ID, subId);
|
|
|
|
|
action.start();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void onConnected() {
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Now connected; starting action");
|
|
|
|
|
|
|
|
|
|
// Clear any pending alarms or connectivity events but leave attempt count alone
|
|
|
|
|
unregister();
|
|
|
|
|
|
|
|
|
|
// Start action
|
|
|
|
|
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
|
|
|
|
action.start();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
// Read and increment attempt number from shared prefs
|
|
|
|
|
final int retryAttempt = getNextRetry();
|
|
|
|
|
register(listener, retryAttempt);
|
|
|
|
|
final int retryAttempt = getNextRetry(subId);
|
|
|
|
|
register(listener, retryAttempt, subId);
|
|
|
|
|
} else {
|
|
|
|
|
// No more pending messages (presumably the message that failed has expired) or it
|
|
|
|
|
// may be possible that a send and a download are already in process.
|
|
|
|
|
// Clear retry attempt count.
|
|
|
|
|
// TODO Might be premature if send and download in process...
|
|
|
|
|
// but worst case means we try to send a bit more often.
|
|
|
|
|
setRetry(0);
|
|
|
|
|
|
|
|
|
|
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
|
|
|
|
|
LogUtil.v(TAG, "ProcessPendingMessagesAction: No more pending messages");
|
|
|
|
|
}
|
|
|
|
|
// but worst case means we try to send a bit more often.
|
|
|
|
|
setRetry(0, subId);
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: No more pending messages");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void register(final ConnectivityListener listener, final int retryAttempt) {
|
|
|
|
|
private static void register(final ConnectivityListener listener, final int retryAttempt,
|
|
|
|
|
int subId) {
|
|
|
|
|
int retryNumber = retryAttempt;
|
|
|
|
|
|
|
|
|
|
// Register to be notified about connectivity changes
|
|
|
|
|
DataModel.get().getConnectivityUtil().register(listener);
|
|
|
|
|
ConnectivityUtil connectivityUtil = DataModelImpl.getConnectivityUtil(subId);
|
|
|
|
|
if (connectivityUtil != null) {
|
|
|
|
|
connectivityUtil.register(listener);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
|
|
|
|
action.actionParameters.putInt(KEY_SUB_ID, subId);
|
|
|
|
|
final long initialBackoffMs = BugleGservices.get().getLong(
|
|
|
|
|
BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS,
|
|
|
|
|
BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS_DEFAULT);
|
|
|
|
@@ -179,31 +173,34 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|
|
|
|
while (retryNumber > 0 && nextDelayMs < maxDelayMs);
|
|
|
|
|
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Registering for retry #" + retryAttempt
|
|
|
|
|
+ " in " + delayMs + " ms");
|
|
|
|
|
+ " in " + delayMs + " ms for subId " + subId);
|
|
|
|
|
|
|
|
|
|
action.schedule(PENDING_INTENT_REQUEST_CODE, delayMs);
|
|
|
|
|
action.schedule(PENDING_INTENT_BASE_REQUEST_CODE + subId, delayMs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void unregister() {
|
|
|
|
|
private static void unregister(final int subId) {
|
|
|
|
|
// Clear any pending alarms or connectivity events
|
|
|
|
|
DataModel.get().getConnectivityUtil().unregister();
|
|
|
|
|
ConnectivityUtil connectivityUtil = DataModelImpl.getConnectivityUtil(subId);
|
|
|
|
|
if (connectivityUtil != null) {
|
|
|
|
|
connectivityUtil.unregister();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
|
|
|
|
action.schedule(PENDING_INTENT_REQUEST_CODE, Long.MAX_VALUE);
|
|
|
|
|
action.schedule(PENDING_INTENT_BASE_REQUEST_CODE + subId, Long.MAX_VALUE);
|
|
|
|
|
|
|
|
|
|
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
|
|
|
|
|
LogUtil.v(TAG, "ProcessPendingMessagesAction: Unregistering for connectivity changed "
|
|
|
|
|
+ "events and clearing scheduled alarm");
|
|
|
|
|
+ "events and clearing scheduled alarm for subId " + subId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void setRetry(final int retryAttempt) {
|
|
|
|
|
final BuglePrefs prefs = Factory.get().getApplicationPrefs();
|
|
|
|
|
private static void setRetry(final int retryAttempt, int subId) {
|
|
|
|
|
final BuglePrefs prefs = Factory.get().getSubscriptionPrefs(subId);
|
|
|
|
|
prefs.putInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, retryAttempt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int getNextRetry() {
|
|
|
|
|
final BuglePrefs prefs = Factory.get().getApplicationPrefs();
|
|
|
|
|
private static int getNextRetry(int subId) {
|
|
|
|
|
final BuglePrefs prefs = Factory.get().getSubscriptionPrefs(subId);
|
|
|
|
|
final int retryAttempt =
|
|
|
|
|
prefs.getInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, 0) + 1;
|
|
|
|
|
prefs.putInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, retryAttempt);
|
|
|
|
@@ -215,21 +212,27 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Read from the DB and determine if there are any messages we should process
|
|
|
|
|
*
|
|
|
|
|
* @param subId the subId
|
|
|
|
|
* @return true if we have pending messages
|
|
|
|
|
*/
|
|
|
|
|
private static boolean getHavePendingMessages() {
|
|
|
|
|
private static boolean getHavePendingMessages(final int subId) {
|
|
|
|
|
final DatabaseWrapper db = DataModel.get().getDatabase();
|
|
|
|
|
final long now = System.currentTimeMillis();
|
|
|
|
|
final String selfId = ParticipantData.getParticipantId(db, subId);
|
|
|
|
|
if (selfId == null) {
|
|
|
|
|
// This could be happened before refreshing participant.
|
|
|
|
|
LogUtil.w(TAG, "ProcessPendingMessagesAction: selfId is null for subId " + subId);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (int subId : getActiveSubscriptionIds()) {
|
|
|
|
|
final String toSendMessageId = findNextMessageToSend(db, now, subId);
|
|
|
|
|
if (toSendMessageId != null) {
|
|
|
|
|
final String toSendMessageId = findNextMessageToSend(db, now, selfId);
|
|
|
|
|
if (toSendMessageId != null) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
final String toDownloadMessageId = findNextMessageToDownload(db, now, selfId);
|
|
|
|
|
if (toDownloadMessageId != null) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
final String toDownloadMessageId = findNextMessageToDownload(db, now, subId);
|
|
|
|
|
if (toDownloadMessageId != null) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Messages may be in the process of sending/downloading even when there are no pending
|
|
|
|
@@ -237,76 +240,65 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int[] getActiveSubscriptionIds() {
|
|
|
|
|
if (!OsUtil.isAtLeastL_MR1()) {
|
|
|
|
|
return new int[] { ParticipantData.DEFAULT_SELF_SUB_ID };
|
|
|
|
|
}
|
|
|
|
|
List<SubscriptionInfo> subscriptions = PhoneUtils.getDefault().toLMr1()
|
|
|
|
|
.getActiveSubscriptionInfoList();
|
|
|
|
|
|
|
|
|
|
int numSubs = subscriptions.size();
|
|
|
|
|
int[] result = new int[numSubs];
|
|
|
|
|
for (int i = 0; i < numSubs; i++) {
|
|
|
|
|
result[i] = subscriptions.get(i).getSubscriptionId();
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Queue any pending actions
|
|
|
|
|
*
|
|
|
|
|
* @param actionState
|
|
|
|
|
* @return true if action queued (or no actions to queue) else false
|
|
|
|
|
*/
|
|
|
|
|
private boolean queueActions(final Action processingAction) {
|
|
|
|
|
final DatabaseWrapper db = DataModel.get().getDatabase();
|
|
|
|
|
final long now = System.currentTimeMillis();
|
|
|
|
|
boolean succeeded = false;
|
|
|
|
|
boolean succeeded = true;
|
|
|
|
|
final int subId = processingAction.actionParameters
|
|
|
|
|
.getInt(KEY_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID);
|
|
|
|
|
|
|
|
|
|
// Will queue no more than one message per subscription to send plus one message to download
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Start queueing for subId " + subId);
|
|
|
|
|
|
|
|
|
|
final String selfId = ParticipantData.getParticipantId(db, subId);
|
|
|
|
|
if (selfId == null) {
|
|
|
|
|
// This could be happened before refreshing participant.
|
|
|
|
|
LogUtil.w(TAG, "ProcessPendingMessagesAction: selfId is null");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Will queue no more than one message to send plus one message to download
|
|
|
|
|
// This keeps outgoing messages "in order" but allow downloads to happen even if sending
|
|
|
|
|
// gets blocked until messages time out. Manual resend bumps messages to head of queue.
|
|
|
|
|
for (int subId : getActiveSubscriptionIds()) {
|
|
|
|
|
final String toSendMessageId = findNextMessageToSend(db, now, subId);
|
|
|
|
|
final String toDownloadMessageId = findNextMessageToDownload(db, now, subId);
|
|
|
|
|
if (toSendMessageId != null) {
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message " + toSendMessageId
|
|
|
|
|
+ " for sending");
|
|
|
|
|
// This could queue nothing
|
|
|
|
|
if (!SendMessageAction.queueForSendInBackground(toSendMessageId,
|
|
|
|
|
processingAction)) {
|
|
|
|
|
LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
|
|
|
|
|
+ toSendMessageId + " for sending");
|
|
|
|
|
} else {
|
|
|
|
|
succeeded = true;
|
|
|
|
|
}
|
|
|
|
|
// gets blocked until messages time out. Manual resend bumps messages to head of queue.
|
|
|
|
|
final String toSendMessageId = findNextMessageToSend(db, now, selfId);
|
|
|
|
|
final String toDownloadMessageId = findNextMessageToDownload(db, now, selfId);
|
|
|
|
|
if (toSendMessageId != null) {
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message " + toSendMessageId
|
|
|
|
|
+ " for sending");
|
|
|
|
|
// This could queue nothing
|
|
|
|
|
if (!SendMessageAction.queueForSendInBackground(toSendMessageId, processingAction)) {
|
|
|
|
|
LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
|
|
|
|
|
+ toSendMessageId + " for sending");
|
|
|
|
|
succeeded = false;
|
|
|
|
|
}
|
|
|
|
|
if (toDownloadMessageId != null) {
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message "
|
|
|
|
|
}
|
|
|
|
|
if (toDownloadMessageId != null) {
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message " + toDownloadMessageId
|
|
|
|
|
+ " for download");
|
|
|
|
|
// This could queue nothing
|
|
|
|
|
if (!DownloadMmsAction.queueMmsForDownloadInBackground(toDownloadMessageId,
|
|
|
|
|
processingAction)) {
|
|
|
|
|
LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
|
|
|
|
|
+ toDownloadMessageId + " for download");
|
|
|
|
|
// This could queue nothing
|
|
|
|
|
if (!DownloadMmsAction.queueMmsForDownloadInBackground(toDownloadMessageId,
|
|
|
|
|
processingAction)) {
|
|
|
|
|
LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
|
|
|
|
|
+ toDownloadMessageId + " for download");
|
|
|
|
|
} else {
|
|
|
|
|
succeeded = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
if (toSendMessageId == null && toDownloadMessageId == null) {
|
|
|
|
|
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
|
|
|
|
|
LogUtil.d(TAG, "ProcessPendingMessagesAction: No messages to send or download");
|
|
|
|
|
}
|
|
|
|
|
succeeded = true;
|
|
|
|
|
succeeded = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (toSendMessageId == null && toDownloadMessageId == null) {
|
|
|
|
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: No messages to send or download");
|
|
|
|
|
}
|
|
|
|
|
return succeeded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected Object executeAction() {
|
|
|
|
|
final int subId = actionParameters.getInt(KEY_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID);
|
|
|
|
|
// If triggered by alarm will not have unregistered yet
|
|
|
|
|
unregister();
|
|
|
|
|
unregister(subId);
|
|
|
|
|
|
|
|
|
|
if (PhoneUtils.getDefault().isDefaultSmsApp()) {
|
|
|
|
|
queueActions(this);
|
|
|
|
@@ -320,83 +312,57 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String prefixColumnWithTable(final String tableName, final String column) {
|
|
|
|
|
return tableName + "." + column;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String[] prefixProjectionWithTable(final String tableName,
|
|
|
|
|
final String[] projection) {
|
|
|
|
|
String[] result = new String[projection.length];
|
|
|
|
|
for (int i = 0; i < projection.length; i++) {
|
|
|
|
|
result[i] = prefixColumnWithTable(tableName, projection[i]);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String findNextMessageToSend(final DatabaseWrapper db, final long now,
|
|
|
|
|
final int subId) {
|
|
|
|
|
final String selfId) {
|
|
|
|
|
String toSendMessageId = null;
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
Cursor sending = null;
|
|
|
|
|
Cursor cursor = null;
|
|
|
|
|
int sendingCnt = 0;
|
|
|
|
|
int pendingCnt = 0;
|
|
|
|
|
int failedCnt = 0;
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
String[] projection = prefixProjectionWithTable(DatabaseHelper.MESSAGES_TABLE,
|
|
|
|
|
MessageData.getProjection());
|
|
|
|
|
String subIdClause =
|
|
|
|
|
prefixColumnWithTable(DatabaseHelper.MESSAGES_TABLE,
|
|
|
|
|
MessageColumns.SELF_PARTICIPANT_ID)
|
|
|
|
|
+ " = "
|
|
|
|
|
+ prefixColumnWithTable(DatabaseHelper.PARTICIPANTS_TABLE,
|
|
|
|
|
ParticipantColumns._ID)
|
|
|
|
|
+ " AND " + ParticipantColumns.SUB_ID + " =?";
|
|
|
|
|
|
|
|
|
|
// First check to see if we have any messages already sending
|
|
|
|
|
sending = db.query(DatabaseHelper.MESSAGES_TABLE + ","
|
|
|
|
|
+ DatabaseHelper.PARTICIPANTS_TABLE,
|
|
|
|
|
projection,
|
|
|
|
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?)"
|
|
|
|
|
+ " AND " + subIdClause,
|
|
|
|
|
new String[]{Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_SENDING),
|
|
|
|
|
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_RESENDING),
|
|
|
|
|
Integer.toString(subId)},
|
|
|
|
|
null,
|
|
|
|
|
null,
|
|
|
|
|
DatabaseHelper.MessageColumns.RECEIVED_TIMESTAMP + " ASC");
|
|
|
|
|
final boolean messageCurrentlySending = sending.moveToNext();
|
|
|
|
|
sendingCnt = sending.getCount();
|
|
|
|
|
// Look for messages we could send
|
|
|
|
|
final ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseHelper.MessageColumns.STATUS,
|
|
|
|
|
MessageData.BUGLE_STATUS_OUTGOING_FAILED);
|
|
|
|
|
cursor = db.query(DatabaseHelper.MESSAGES_TABLE + ","
|
|
|
|
|
+ DatabaseHelper.PARTICIPANTS_TABLE,
|
|
|
|
|
projection,
|
|
|
|
|
DatabaseHelper.MessageColumns.STATUS + " IN ("
|
|
|
|
|
+ MessageData.BUGLE_STATUS_OUTGOING_YET_TO_SEND + ","
|
|
|
|
|
+ MessageData.BUGLE_STATUS_OUTGOING_AWAITING_RETRY + ")"
|
|
|
|
|
+ " AND " + subIdClause,
|
|
|
|
|
new String[]{Integer.toString(subId)},
|
|
|
|
|
sendingCnt = (int) db.queryNumEntries(DatabaseHelper.MESSAGES_TABLE,
|
|
|
|
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?) AND "
|
|
|
|
|
+ DatabaseHelper.MessageColumns.SELF_PARTICIPANT_ID + " =? ",
|
|
|
|
|
new String[] {
|
|
|
|
|
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_SENDING),
|
|
|
|
|
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_RESENDING),
|
|
|
|
|
selfId}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Look for messages we cound send
|
|
|
|
|
cursor = db.query(DatabaseHelper.MESSAGES_TABLE,
|
|
|
|
|
MessageData.getProjection(),
|
|
|
|
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?) AND "
|
|
|
|
|
+ DatabaseHelper.MessageColumns.SELF_PARTICIPANT_ID + " =? ",
|
|
|
|
|
new String[] {
|
|
|
|
|
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_YET_TO_SEND),
|
|
|
|
|
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_AWAITING_RETRY),
|
|
|
|
|
selfId
|
|
|
|
|
},
|
|
|
|
|
null,
|
|
|
|
|
null,
|
|
|
|
|
DatabaseHelper.MessageColumns.RECEIVED_TIMESTAMP + " ASC");
|
|
|
|
|
pendingCnt = cursor.getCount();
|
|
|
|
|
|
|
|
|
|
final ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseHelper.MessageColumns.STATUS,
|
|
|
|
|
MessageData.BUGLE_STATUS_OUTGOING_FAILED);
|
|
|
|
|
|
|
|
|
|
while (cursor.moveToNext()) {
|
|
|
|
|
final MessageData message = new MessageData();
|
|
|
|
|
message.bind(cursor);
|
|
|
|
|
if (message.getInResendWindow(now)) {
|
|
|
|
|
// If no messages currently sending
|
|
|
|
|
if (!messageCurrentlySending) {
|
|
|
|
|
if (sendingCnt == 0) {
|
|
|
|
|
// Resend this message
|
|
|
|
|
toSendMessageId = message.getMessageId();
|
|
|
|
|
// Before queuing the message for resending, check if the message's self is
|
|
|
|
|
// active. If not, switch back to the system's default subscription.
|
|
|
|
|
if (OsUtil.isAtLeastL_MR1()) {
|
|
|
|
|
final ParticipantData messageSelf = BugleDatabaseOperations
|
|
|
|
|
.getExistingParticipant(db, message.getSelfId());
|
|
|
|
|
.getExistingParticipant(db, selfId);
|
|
|
|
|
if (messageSelf == null || !messageSelf.isActiveSubscription()) {
|
|
|
|
|
final ParticipantData defaultSelf = BugleDatabaseOperations
|
|
|
|
|
.getOrCreateSelf(db, PhoneUtils.getDefault()
|
|
|
|
@@ -429,9 +395,6 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|
|
|
|
if (cursor != null) {
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
if (sending != null) {
|
|
|
|
|
sending.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
|
|
|
|
@@ -445,48 +408,33 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String findNextMessageToDownload(final DatabaseWrapper db, final long now,
|
|
|
|
|
final int subId) {
|
|
|
|
|
final String selfId) {
|
|
|
|
|
String toDownloadMessageId = null;
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
Cursor cursor = null;
|
|
|
|
|
int downloadingCnt = 0;
|
|
|
|
|
int pendingCnt = 0;
|
|
|
|
|
db.beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
String[] projection = prefixProjectionWithTable(DatabaseHelper.MESSAGES_TABLE,
|
|
|
|
|
MessageData.getProjection());
|
|
|
|
|
String subIdClause =
|
|
|
|
|
prefixColumnWithTable(DatabaseHelper.MESSAGES_TABLE,
|
|
|
|
|
MessageColumns.SELF_PARTICIPANT_ID)
|
|
|
|
|
+ " = "
|
|
|
|
|
+ prefixColumnWithTable(DatabaseHelper.PARTICIPANTS_TABLE,
|
|
|
|
|
ParticipantColumns._ID)
|
|
|
|
|
+ " AND " + ParticipantColumns.SUB_ID + " =?";
|
|
|
|
|
|
|
|
|
|
// First check if we have any messages already downloading
|
|
|
|
|
downloadingCnt = (int) db.queryNumEntries(DatabaseHelper.MESSAGES_TABLE
|
|
|
|
|
+ "," + DatabaseHelper.PARTICIPANTS_TABLE,
|
|
|
|
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?)"
|
|
|
|
|
+ " AND " + subIdClause,
|
|
|
|
|
downloadingCnt = (int) db.queryNumEntries(DatabaseHelper.MESSAGES_TABLE,
|
|
|
|
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?) AND "
|
|
|
|
|
+ DatabaseHelper.MessageColumns.SELF_PARTICIPANT_ID + " =?",
|
|
|
|
|
new String[] {
|
|
|
|
|
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING),
|
|
|
|
|
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING),
|
|
|
|
|
Integer.toString(subId)
|
|
|
|
|
selfId
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// TODO: This query is not actually needed if downloadingCnt == 0.
|
|
|
|
|
cursor = db.query(DatabaseHelper.MESSAGES_TABLE + ","
|
|
|
|
|
+ DatabaseHelper.PARTICIPANTS_TABLE,
|
|
|
|
|
projection,
|
|
|
|
|
DatabaseHelper.MessageColumns.STATUS + " =? OR "
|
|
|
|
|
+ DatabaseHelper.MessageColumns.STATUS + " =?"
|
|
|
|
|
+ " AND " + subIdClause,
|
|
|
|
|
cursor = db.query(DatabaseHelper.MESSAGES_TABLE,
|
|
|
|
|
MessageData.getProjection(),
|
|
|
|
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?) AND "
|
|
|
|
|
+ DatabaseHelper.MessageColumns.SELF_PARTICIPANT_ID + " =? ",
|
|
|
|
|
new String[]{
|
|
|
|
|
Integer.toString(
|
|
|
|
|
MessageData.BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD),
|
|
|
|
|
Integer.toString(
|
|
|
|
|
MessageData.BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD),
|
|
|
|
|
Integer.toString(
|
|
|
|
|
subId)
|
|
|
|
|
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD),
|
|
|
|
|
Integer.toString(
|
|
|
|
|
MessageData.BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD),
|
|
|
|
|
selfId
|
|
|
|
|
},
|
|
|
|
|
null,
|
|
|
|
|
null,
|
|
|
|
|