ProcessPendingMessagesAction works based on subscriptions
PorcessPendingMessagesAction queues one message for sending/downloading associated with a subscription triggering current action at a time. And the ConnectivityUtil also works based on subscriptions so that pending messages can be processed regardless of other phones' state in multi-sim case. It includes cleanup code as well. Test: Manual Change-Id: Id6b4f4a0aa6a3291e7a4d8a5d3f0fbb9db3c5b86 Signed-off-by: Taesu Lee <taesu82.lee@samsung.com>
This commit is contained in:
@@ -965,7 +965,7 @@ public class BugleDatabaseOperations {
|
|||||||
return participant;
|
return participant;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getSelfSubscriptionId(final DatabaseWrapper dbWrapper,
|
public static int getSelfSubscriptionId(final DatabaseWrapper dbWrapper,
|
||||||
final String selfParticipantId) {
|
final String selfParticipantId) {
|
||||||
final ParticipantData selfParticipant = BugleDatabaseOperations.getExistingParticipant(
|
final ParticipantData selfParticipant = BugleDatabaseOperations.getExistingParticipant(
|
||||||
dbWrapper, selfParticipantId);
|
dbWrapper, selfParticipantId);
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ import com.android.messaging.datamodel.data.SettingsData.SettingsDataListener;
|
|||||||
import com.android.messaging.datamodel.data.SubscriptionListData;
|
import com.android.messaging.datamodel.data.SubscriptionListData;
|
||||||
import com.android.messaging.datamodel.data.VCardContactItemData;
|
import com.android.messaging.datamodel.data.VCardContactItemData;
|
||||||
import com.android.messaging.util.Assert.DoesNotRunOnMainThread;
|
import com.android.messaging.util.Assert.DoesNotRunOnMainThread;
|
||||||
import com.android.messaging.util.ConnectivityUtil;
|
|
||||||
|
|
||||||
public abstract class DataModel {
|
public abstract class DataModel {
|
||||||
private String mFocusedConversation;
|
private String mFocusedConversation;
|
||||||
@@ -152,7 +151,5 @@ public abstract class DataModel {
|
|||||||
|
|
||||||
public abstract void onApplicationCreated();
|
public abstract void onApplicationCreated();
|
||||||
|
|
||||||
public abstract ConnectivityUtil getConnectivityUtil();
|
|
||||||
|
|
||||||
public abstract SyncManager getSyncManager();
|
public abstract SyncManager getSyncManager();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,22 +57,33 @@ import com.android.messaging.util.LogUtil;
|
|||||||
import com.android.messaging.util.OsUtil;
|
import com.android.messaging.util.OsUtil;
|
||||||
import com.android.messaging.util.PhoneUtils;
|
import com.android.messaging.util.PhoneUtils;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class DataModelImpl extends DataModel {
|
public class DataModelImpl extends DataModel {
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final ActionService mActionService;
|
private final ActionService mActionService;
|
||||||
private final BackgroundWorker mDataModelWorker;
|
private final BackgroundWorker mDataModelWorker;
|
||||||
private final DatabaseHelper mDatabaseHelper;
|
private final DatabaseHelper mDatabaseHelper;
|
||||||
private final ConnectivityUtil mConnectivityUtil;
|
|
||||||
private final SyncManager mSyncManager;
|
private final SyncManager mSyncManager;
|
||||||
|
|
||||||
|
// Cached ConnectivityUtil instance for Pre-L_MR1
|
||||||
|
private static ConnectivityUtil sConnectivityUtilInstanceCachePreLMR1 = null;
|
||||||
|
// Cached ConnectivityUtil subId->instance for L_MR1 and beyond
|
||||||
|
private static final ConcurrentHashMap<Integer, ConnectivityUtil>
|
||||||
|
sConnectivityUtilInstanceCacheLMR1 = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
public DataModelImpl(final Context context) {
|
public DataModelImpl(final Context context) {
|
||||||
super();
|
super();
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mActionService = new ActionService();
|
mActionService = new ActionService();
|
||||||
mDataModelWorker = new BackgroundWorker();
|
mDataModelWorker = new BackgroundWorker();
|
||||||
mDatabaseHelper = DatabaseHelper.getInstance(context);
|
mDatabaseHelper = DatabaseHelper.getInstance(context);
|
||||||
mConnectivityUtil = new ConnectivityUtil(context);
|
|
||||||
mSyncManager = new SyncManager();
|
mSyncManager = new SyncManager();
|
||||||
|
if (OsUtil.isAtLeastL_MR1()) {
|
||||||
|
createConnectivityUtilForLMR1();
|
||||||
|
} else {
|
||||||
|
sConnectivityUtilInstanceCachePreLMR1 = new ConnectivityUtil(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -184,11 +195,6 @@ public class DataModelImpl extends DataModel {
|
|||||||
return mDatabaseHelper.getDatabase();
|
return mDatabaseHelper.getDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConnectivityUtil getConnectivityUtil() {
|
|
||||||
return mConnectivityUtil;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SyncManager getSyncManager() {
|
public SyncManager getSyncManager() {
|
||||||
return mSyncManager;
|
return mSyncManager;
|
||||||
@@ -218,7 +224,8 @@ public class DataModelImpl extends DataModel {
|
|||||||
SyncManager.immediateSync();
|
SyncManager.immediateSync();
|
||||||
|
|
||||||
if (OsUtil.isAtLeastL_MR1()) {
|
if (OsUtil.isAtLeastL_MR1()) {
|
||||||
// Start listening for subscription change events for refreshing self participants.
|
// Start listening for subscription change events for refreshing any data associated
|
||||||
|
// with subscriptions.
|
||||||
PhoneUtils.getDefault().toLMr1().registerOnSubscriptionsChangedListener(
|
PhoneUtils.getDefault().toLMr1().registerOnSubscriptionsChangedListener(
|
||||||
new SubscriptionManager.OnSubscriptionsChangedListener() {
|
new SubscriptionManager.OnSubscriptionsChangedListener() {
|
||||||
@Override
|
@Override
|
||||||
@@ -229,8 +236,31 @@ public class DataModelImpl extends DataModel {
|
|||||||
// gracefully
|
// gracefully
|
||||||
MmsConfig.loadAsync();
|
MmsConfig.loadAsync();
|
||||||
ParticipantRefresh.refreshSelfParticipants();
|
ParticipantRefresh.refreshSelfParticipants();
|
||||||
|
createConnectivityUtilForLMR1();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createConnectivityUtilForLMR1() {
|
||||||
|
PhoneUtils.forEachActiveSubscription(new PhoneUtils.SubscriptionRunnable() {
|
||||||
|
@Override
|
||||||
|
public void runForSubscription(int subId) {
|
||||||
|
// Create the ConnectivityUtil instance for given subId if absent.
|
||||||
|
if (subId <= ParticipantData.DEFAULT_SELF_SUB_ID) {
|
||||||
|
subId = PhoneUtils.getDefault().getDefaultSmsSubscriptionId();
|
||||||
|
}
|
||||||
|
sConnectivityUtilInstanceCacheLMR1.computeIfAbsent(
|
||||||
|
subId, key -> new ConnectivityUtil(mContext, key));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConnectivityUtil getConnectivityUtil(final int subId) {
|
||||||
|
if (OsUtil.isAtLeastL_MR1()) {
|
||||||
|
return sConnectivityUtilInstanceCacheLMR1.get(subId);
|
||||||
|
} else {
|
||||||
|
return sConnectivityUtilInstanceCachePreLMR1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import androidx.core.app.JobIntentService;
|
|||||||
|
|
||||||
import com.android.messaging.Factory;
|
import com.android.messaging.Factory;
|
||||||
import com.android.messaging.datamodel.DataModel;
|
import com.android.messaging.datamodel.DataModel;
|
||||||
import com.android.messaging.util.ConnectivityUtil;
|
|
||||||
import com.android.messaging.util.LogUtil;
|
import com.android.messaging.util.LogUtil;
|
||||||
import com.android.messaging.util.LoggingTimer;
|
import com.android.messaging.util.LoggingTimer;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
@@ -134,7 +133,6 @@ public class ActionServiceImpl extends JobIntentService {
|
|||||||
protected static final String BUNDLE_ACTION = "bundle_action";
|
protected static final String BUNDLE_ACTION = "bundle_action";
|
||||||
|
|
||||||
private BackgroundWorker mBackgroundWorker;
|
private BackgroundWorker mBackgroundWorker;
|
||||||
private ConnectivityUtil mConnectivityUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate an intent with a specific opcode.
|
* Allocate an intent with a specific opcode.
|
||||||
@@ -213,14 +211,11 @@ public class ActionServiceImpl extends JobIntentService {
|
|||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
mBackgroundWorker = DataModel.get().getBackgroundWorkerForActionService();
|
mBackgroundWorker = DataModel.get().getBackgroundWorkerForActionService();
|
||||||
mConnectivityUtil = DataModel.get().getConnectivityUtil();
|
|
||||||
mConnectivityUtil.registerForSignalStrength();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
mConnectivityUtil.unregisterForSignalStrength();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -60,13 +60,12 @@ public class FixupMessageStatusOnStartupAction extends Action implements Parcela
|
|||||||
final ContentValues values = new ContentValues();
|
final ContentValues values = new ContentValues();
|
||||||
values.put(DatabaseHelper.MessageColumns.STATUS,
|
values.put(DatabaseHelper.MessageColumns.STATUS,
|
||||||
MessageData.BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED);
|
MessageData.BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED);
|
||||||
downloadFailedCnt += db.update(DatabaseHelper.MESSAGES_TABLE, values,
|
downloadFailedCnt = db.update(DatabaseHelper.MESSAGES_TABLE, values,
|
||||||
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?)",
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?)",
|
||||||
new String[]{
|
new String[]{
|
||||||
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING),
|
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING),
|
||||||
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING)
|
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING)
|
||||||
});
|
});
|
||||||
values.clear();
|
|
||||||
|
|
||||||
values.clear();
|
values.clear();
|
||||||
values.put(DatabaseHelper.MessageColumns.STATUS,
|
values.put(DatabaseHelper.MessageColumns.STATUS,
|
||||||
|
|||||||
@@ -118,7 +118,6 @@ public class InsertNewMessageAction extends Action implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Object executeAction() {
|
protected Object executeAction() {
|
||||||
LogUtil.i(TAG, "InsertNewMessageAction: inserting new message");
|
|
||||||
MessageData message = actionParameters.getParcelable(KEY_MESSAGE);
|
MessageData message = actionParameters.getParcelable(KEY_MESSAGE);
|
||||||
if (message == null) {
|
if (message == null) {
|
||||||
LogUtil.i(TAG, "InsertNewMessageAction: Creating MessageData with provided data");
|
LogUtil.i(TAG, "InsertNewMessageAction: Creating MessageData with provided data");
|
||||||
@@ -151,6 +150,8 @@ public class InsertNewMessageAction extends Action implements Parcelable {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
final int subId = self.getSubId();
|
final int subId = self.getSubId();
|
||||||
|
LogUtil.i(TAG, "InsertNewMessageAction: inserting new message for subId " + subId);
|
||||||
|
actionParameters.putInt(KEY_SUB_ID, subId);
|
||||||
|
|
||||||
// TODO: Work out whether to send with SMS or MMS (taking into account recipients)?
|
// TODO: Work out whether to send with SMS or MMS (taking into account recipients)?
|
||||||
final boolean isSms = (message.getProtocol() == MessageData.PROTOCOL_SMS);
|
final boolean isSms = (message.getProtocol() == MessageData.PROTOCOL_SMS);
|
||||||
|
|||||||
@@ -17,76 +17,83 @@
|
|||||||
package com.android.messaging.datamodel.action;
|
package com.android.messaging.datamodel.action;
|
||||||
|
|
||||||
import android.content.ContentValues;
|
import android.content.ContentValues;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import android.telephony.ServiceState;
|
import android.telephony.ServiceState;
|
||||||
import android.telephony.SubscriptionInfo;
|
|
||||||
|
|
||||||
import com.android.messaging.Factory;
|
import com.android.messaging.Factory;
|
||||||
import com.android.messaging.datamodel.BugleDatabaseOperations;
|
import com.android.messaging.datamodel.BugleDatabaseOperations;
|
||||||
import com.android.messaging.datamodel.DataModel;
|
import com.android.messaging.datamodel.DataModel;
|
||||||
|
import com.android.messaging.datamodel.DataModelImpl;
|
||||||
import com.android.messaging.datamodel.DatabaseHelper;
|
import com.android.messaging.datamodel.DatabaseHelper;
|
||||||
import com.android.messaging.datamodel.DatabaseHelper.MessageColumns;
|
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.DatabaseWrapper;
|
||||||
import com.android.messaging.datamodel.MessagingContentProvider;
|
import com.android.messaging.datamodel.MessagingContentProvider;
|
||||||
import com.android.messaging.datamodel.data.MessageData;
|
import com.android.messaging.datamodel.data.MessageData;
|
||||||
import com.android.messaging.datamodel.data.ParticipantData;
|
import com.android.messaging.datamodel.data.ParticipantData;
|
||||||
import com.android.messaging.sms.MmsUtils;
|
|
||||||
import com.android.messaging.util.BugleGservices;
|
import com.android.messaging.util.BugleGservices;
|
||||||
import com.android.messaging.util.BugleGservicesKeys;
|
import com.android.messaging.util.BugleGservicesKeys;
|
||||||
import com.android.messaging.util.BuglePrefs;
|
import com.android.messaging.util.BuglePrefs;
|
||||||
import com.android.messaging.util.BuglePrefsKeys;
|
import com.android.messaging.util.BuglePrefsKeys;
|
||||||
|
import com.android.messaging.util.ConnectivityUtil;
|
||||||
import com.android.messaging.util.ConnectivityUtil.ConnectivityListener;
|
import com.android.messaging.util.ConnectivityUtil.ConnectivityListener;
|
||||||
import com.android.messaging.util.LogUtil;
|
import com.android.messaging.util.LogUtil;
|
||||||
import com.android.messaging.util.OsUtil;
|
import com.android.messaging.util.OsUtil;
|
||||||
import com.android.messaging.util.PhoneUtils;
|
import com.android.messaging.util.PhoneUtils;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Action used to lookup any messages in the pending send/download state and either fail them or
|
* 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
|
* retry their action based on subscriptions. This action only initiates one retry at a time for
|
||||||
* triggered by successful sending of a message, network status change or exponential backoff timer.
|
* 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 {
|
public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
||||||
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
|
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() {
|
public static void processFirstPendingMessage() {
|
||||||
|
PhoneUtils.forEachActiveSubscription(new PhoneUtils.SubscriptionRunnable() {
|
||||||
|
@Override
|
||||||
|
public void runForSubscription(final int subId) {
|
||||||
// Clear any pending alarms or connectivity events
|
// Clear any pending alarms or connectivity events
|
||||||
unregister();
|
unregister(subId);
|
||||||
// Clear retry count
|
// Clear retry count
|
||||||
setRetry(0);
|
setRetry(0, subId);
|
||||||
|
|
||||||
// Start action
|
// Start action
|
||||||
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
||||||
|
action.actionParameters.putInt(KEY_SUB_ID, subId);
|
||||||
action.start();
|
action.start();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static void scheduleProcessPendingMessagesAction(final boolean failed,
|
public static void scheduleProcessPendingMessagesAction(final boolean failed,
|
||||||
final Action processingAction) {
|
final Action processingAction) {
|
||||||
|
final int subId = processingAction.actionParameters
|
||||||
|
.getInt(KEY_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID);
|
||||||
LogUtil.i(TAG, "ProcessPendingMessagesAction: Scheduling pending messages"
|
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
|
// 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.
|
// is currently running or we will run now or register if pending actions possible.
|
||||||
unregister();
|
unregister(subId);
|
||||||
|
|
||||||
final boolean isDefaultSmsApp = PhoneUtils.getDefault().isDefaultSmsApp();
|
final boolean isDefaultSmsApp = PhoneUtils.getDefault().isDefaultSmsApp();
|
||||||
boolean scheduleAlarm = false;
|
boolean scheduleAlarm = false;
|
||||||
// If message succeeded and if Bugle is default SMS app just carry on with next message
|
// If message succeeded and if Bugle is default SMS app just carry on with next message
|
||||||
if (!failed && isDefaultSmsApp) {
|
if (!failed && isDefaultSmsApp) {
|
||||||
// Clear retry attempt count as something just succeeded
|
// Clear retry attempt count as something just succeeded
|
||||||
setRetry(0);
|
setRetry(0, subId);
|
||||||
|
|
||||||
// Lookup and queue next message for immediate processing by background worker
|
// Lookup and queue next message for each sending/downloading for immediate processing
|
||||||
// iff there are no pending messages this will do nothing and return true.
|
// by background worker. If there are no pending messages, this will do nothing and
|
||||||
|
// return true.
|
||||||
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
||||||
if (action.queueActions(processingAction)) {
|
if (action.queueActions(processingAction)) {
|
||||||
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
|
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
|
||||||
@@ -103,66 +110,53 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|||||||
scheduleAlarm = true;
|
scheduleAlarm = true;
|
||||||
LogUtil.w(TAG, "ProcessPendingMessagesAction: Action failed to queue; retrying");
|
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
|
// Still have a pending message that needs to be queued for processing
|
||||||
final ConnectivityListener listener = new ConnectivityListener() {
|
final ConnectivityListener listener = new ConnectivityListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onConnectivityStateChanged(final Context context, final Intent intent) {
|
public void onPhoneStateChanged(final int serviceState) {
|
||||||
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) {
|
|
||||||
if (serviceState == ServiceState.STATE_IN_SERVICE) {
|
if (serviceState == ServiceState.STATE_IN_SERVICE) {
|
||||||
onConnected();
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Now connected for subId "
|
||||||
}
|
+ subId + ", starting action");
|
||||||
}
|
|
||||||
|
|
||||||
private void onConnected() {
|
// Clear any pending alarms or connectivity events but leave attempt count
|
||||||
LogUtil.i(TAG, "ProcessPendingMessagesAction: Now connected; starting action");
|
// alone
|
||||||
|
unregister(subId);
|
||||||
// Clear any pending alarms or connectivity events but leave attempt count alone
|
|
||||||
unregister();
|
|
||||||
|
|
||||||
// Start action
|
// Start action
|
||||||
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
final ProcessPendingMessagesAction action =
|
||||||
|
new ProcessPendingMessagesAction();
|
||||||
|
action.actionParameters.putInt(KEY_SUB_ID, subId);
|
||||||
action.start();
|
action.start();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
// Read and increment attempt number from shared prefs
|
// Read and increment attempt number from shared prefs
|
||||||
final int retryAttempt = getNextRetry();
|
final int retryAttempt = getNextRetry(subId);
|
||||||
register(listener, retryAttempt);
|
register(listener, retryAttempt, subId);
|
||||||
} else {
|
} else {
|
||||||
// No more pending messages (presumably the message that failed has expired) or it
|
// 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.
|
// may be possible that a send and a download are already in process.
|
||||||
// Clear retry attempt count.
|
// Clear retry attempt count.
|
||||||
// TODO Might be premature if send and download in process...
|
// TODO Might be premature if send and download in process...
|
||||||
// but worst case means we try to send a bit more often.
|
// but worst case means we try to send a bit more often.
|
||||||
setRetry(0);
|
setRetry(0, subId);
|
||||||
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: No more pending messages");
|
||||||
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
|
|
||||||
LogUtil.v(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;
|
int retryNumber = retryAttempt;
|
||||||
|
|
||||||
// Register to be notified about connectivity changes
|
// 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();
|
final ProcessPendingMessagesAction action = new ProcessPendingMessagesAction();
|
||||||
|
action.actionParameters.putInt(KEY_SUB_ID, subId);
|
||||||
final long initialBackoffMs = BugleGservices.get().getLong(
|
final long initialBackoffMs = BugleGservices.get().getLong(
|
||||||
BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS,
|
BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS,
|
||||||
BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS_DEFAULT);
|
BugleGservicesKeys.INITIAL_MESSAGE_RESEND_DELAY_MS_DEFAULT);
|
||||||
@@ -179,31 +173,34 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|||||||
while (retryNumber > 0 && nextDelayMs < maxDelayMs);
|
while (retryNumber > 0 && nextDelayMs < maxDelayMs);
|
||||||
|
|
||||||
LogUtil.i(TAG, "ProcessPendingMessagesAction: Registering for retry #" + retryAttempt
|
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
|
// 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();
|
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)) {
|
if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
|
||||||
LogUtil.v(TAG, "ProcessPendingMessagesAction: Unregistering for connectivity changed "
|
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) {
|
private static void setRetry(final int retryAttempt, int subId) {
|
||||||
final BuglePrefs prefs = Factory.get().getApplicationPrefs();
|
final BuglePrefs prefs = Factory.get().getSubscriptionPrefs(subId);
|
||||||
prefs.putInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, retryAttempt);
|
prefs.putInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, retryAttempt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getNextRetry() {
|
private static int getNextRetry(int subId) {
|
||||||
final BuglePrefs prefs = Factory.get().getApplicationPrefs();
|
final BuglePrefs prefs = Factory.get().getSubscriptionPrefs(subId);
|
||||||
final int retryAttempt =
|
final int retryAttempt =
|
||||||
prefs.getInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, 0) + 1;
|
prefs.getInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, 0) + 1;
|
||||||
prefs.putInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, retryAttempt);
|
prefs.putInt(BuglePrefsKeys.PROCESS_PENDING_MESSAGES_RETRY_COUNT, retryAttempt);
|
||||||
@@ -215,98 +212,93 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Read from the DB and determine if there are any messages we should process
|
* 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
|
* @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 DatabaseWrapper db = DataModel.get().getDatabase();
|
||||||
final long now = System.currentTimeMillis();
|
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, selfId);
|
||||||
final String toSendMessageId = findNextMessageToSend(db, now, subId);
|
|
||||||
if (toSendMessageId != null) {
|
if (toSendMessageId != null) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
final String toDownloadMessageId = findNextMessageToDownload(db, now, subId);
|
final String toDownloadMessageId = findNextMessageToDownload(db, now, selfId);
|
||||||
if (toDownloadMessageId != null) {
|
if (toDownloadMessageId != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Messages may be in the process of sending/downloading even when there are no pending
|
// Messages may be in the process of sending/downloading even when there are no pending
|
||||||
// messages...
|
// messages...
|
||||||
return false;
|
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
|
* Queue any pending actions
|
||||||
|
*
|
||||||
* @param actionState
|
* @param actionState
|
||||||
* @return true if action queued (or no actions to queue) else false
|
* @return true if action queued (or no actions to queue) else false
|
||||||
*/
|
*/
|
||||||
private boolean queueActions(final Action processingAction) {
|
private boolean queueActions(final Action processingAction) {
|
||||||
final DatabaseWrapper db = DataModel.get().getDatabase();
|
final DatabaseWrapper db = DataModel.get().getDatabase();
|
||||||
final long now = System.currentTimeMillis();
|
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
|
// 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.
|
// gets blocked until messages time out. Manual resend bumps messages to head of queue.
|
||||||
for (int subId : getActiveSubscriptionIds()) {
|
final String toSendMessageId = findNextMessageToSend(db, now, selfId);
|
||||||
final String toSendMessageId = findNextMessageToSend(db, now, subId);
|
final String toDownloadMessageId = findNextMessageToDownload(db, now, selfId);
|
||||||
final String toDownloadMessageId = findNextMessageToDownload(db, now, subId);
|
|
||||||
if (toSendMessageId != null) {
|
if (toSendMessageId != null) {
|
||||||
LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message " + toSendMessageId
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message " + toSendMessageId
|
||||||
+ " for sending");
|
+ " for sending");
|
||||||
// This could queue nothing
|
// This could queue nothing
|
||||||
if (!SendMessageAction.queueForSendInBackground(toSendMessageId,
|
if (!SendMessageAction.queueForSendInBackground(toSendMessageId, processingAction)) {
|
||||||
processingAction)) {
|
|
||||||
LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
|
LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
|
||||||
+ toSendMessageId + " for sending");
|
+ toSendMessageId + " for sending");
|
||||||
} else {
|
succeeded = false;
|
||||||
succeeded = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (toDownloadMessageId != null) {
|
if (toDownloadMessageId != null) {
|
||||||
LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message "
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: Queueing message " + toDownloadMessageId
|
||||||
+ toDownloadMessageId + " for download");
|
+ " for download");
|
||||||
// This could queue nothing
|
// This could queue nothing
|
||||||
if (!DownloadMmsAction.queueMmsForDownloadInBackground(toDownloadMessageId,
|
if (!DownloadMmsAction.queueMmsForDownloadInBackground(toDownloadMessageId,
|
||||||
processingAction)) {
|
processingAction)) {
|
||||||
LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
|
LogUtil.w(TAG, "ProcessPendingMessagesAction: Failed to queue message "
|
||||||
+ toDownloadMessageId + " for download");
|
+ toDownloadMessageId + " for download");
|
||||||
} else {
|
succeeded = false;
|
||||||
succeeded = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (toSendMessageId == null && toDownloadMessageId == null) {
|
if (toSendMessageId == null && toDownloadMessageId == null) {
|
||||||
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
|
LogUtil.i(TAG, "ProcessPendingMessagesAction: No messages to send or download");
|
||||||
LogUtil.d(TAG, "ProcessPendingMessagesAction: No messages to send or download");
|
|
||||||
}
|
|
||||||
succeeded = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return succeeded;
|
return succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object executeAction() {
|
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
|
// If triggered by alarm will not have unregistered yet
|
||||||
unregister();
|
unregister(subId);
|
||||||
|
|
||||||
if (PhoneUtils.getDefault().isDefaultSmsApp()) {
|
if (PhoneUtils.getDefault().isDefaultSmsApp()) {
|
||||||
queueActions(this);
|
queueActions(this);
|
||||||
@@ -320,83 +312,57 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|||||||
return null;
|
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,
|
private static String findNextMessageToSend(final DatabaseWrapper db, final long now,
|
||||||
final int subId) {
|
final String selfId) {
|
||||||
String toSendMessageId = null;
|
String toSendMessageId = null;
|
||||||
db.beginTransaction();
|
|
||||||
Cursor sending = null;
|
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
int sendingCnt = 0;
|
int sendingCnt = 0;
|
||||||
int pendingCnt = 0;
|
int pendingCnt = 0;
|
||||||
int failedCnt = 0;
|
int failedCnt = 0;
|
||||||
|
db.beginTransaction();
|
||||||
try {
|
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
|
// First check to see if we have any messages already sending
|
||||||
sending = db.query(DatabaseHelper.MESSAGES_TABLE + ","
|
sendingCnt = (int) db.queryNumEntries(DatabaseHelper.MESSAGES_TABLE,
|
||||||
+ DatabaseHelper.PARTICIPANTS_TABLE,
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?) AND "
|
||||||
projection,
|
+ DatabaseHelper.MessageColumns.SELF_PARTICIPANT_ID + " =? ",
|
||||||
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?)"
|
new String[] {
|
||||||
+ " AND " + subIdClause,
|
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_SENDING),
|
||||||
new String[]{Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_SENDING),
|
|
||||||
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_RESENDING),
|
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_RESENDING),
|
||||||
Integer.toString(subId)},
|
selfId}
|
||||||
null,
|
);
|
||||||
null,
|
|
||||||
DatabaseHelper.MessageColumns.RECEIVED_TIMESTAMP + " ASC");
|
// Look for messages we cound send
|
||||||
final boolean messageCurrentlySending = sending.moveToNext();
|
cursor = db.query(DatabaseHelper.MESSAGES_TABLE,
|
||||||
sendingCnt = sending.getCount();
|
MessageData.getProjection(),
|
||||||
// Look for messages we could send
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?) AND "
|
||||||
final ContentValues values = new ContentValues();
|
+ DatabaseHelper.MessageColumns.SELF_PARTICIPANT_ID + " =? ",
|
||||||
values.put(DatabaseHelper.MessageColumns.STATUS,
|
new String[] {
|
||||||
MessageData.BUGLE_STATUS_OUTGOING_FAILED);
|
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_YET_TO_SEND),
|
||||||
cursor = db.query(DatabaseHelper.MESSAGES_TABLE + ","
|
Integer.toString(MessageData.BUGLE_STATUS_OUTGOING_AWAITING_RETRY),
|
||||||
+ DatabaseHelper.PARTICIPANTS_TABLE,
|
selfId
|
||||||
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)},
|
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
DatabaseHelper.MessageColumns.RECEIVED_TIMESTAMP + " ASC");
|
DatabaseHelper.MessageColumns.RECEIVED_TIMESTAMP + " ASC");
|
||||||
pendingCnt = cursor.getCount();
|
pendingCnt = cursor.getCount();
|
||||||
|
|
||||||
|
final ContentValues values = new ContentValues();
|
||||||
|
values.put(DatabaseHelper.MessageColumns.STATUS,
|
||||||
|
MessageData.BUGLE_STATUS_OUTGOING_FAILED);
|
||||||
|
|
||||||
while (cursor.moveToNext()) {
|
while (cursor.moveToNext()) {
|
||||||
final MessageData message = new MessageData();
|
final MessageData message = new MessageData();
|
||||||
message.bind(cursor);
|
message.bind(cursor);
|
||||||
if (message.getInResendWindow(now)) {
|
if (message.getInResendWindow(now)) {
|
||||||
// If no messages currently sending
|
// If no messages currently sending
|
||||||
if (!messageCurrentlySending) {
|
if (sendingCnt == 0) {
|
||||||
// Resend this message
|
// Resend this message
|
||||||
toSendMessageId = message.getMessageId();
|
toSendMessageId = message.getMessageId();
|
||||||
// Before queuing the message for resending, check if the message's self is
|
// Before queuing the message for resending, check if the message's self is
|
||||||
// active. If not, switch back to the system's default subscription.
|
// active. If not, switch back to the system's default subscription.
|
||||||
if (OsUtil.isAtLeastL_MR1()) {
|
if (OsUtil.isAtLeastL_MR1()) {
|
||||||
final ParticipantData messageSelf = BugleDatabaseOperations
|
final ParticipantData messageSelf = BugleDatabaseOperations
|
||||||
.getExistingParticipant(db, message.getSelfId());
|
.getExistingParticipant(db, selfId);
|
||||||
if (messageSelf == null || !messageSelf.isActiveSubscription()) {
|
if (messageSelf == null || !messageSelf.isActiveSubscription()) {
|
||||||
final ParticipantData defaultSelf = BugleDatabaseOperations
|
final ParticipantData defaultSelf = BugleDatabaseOperations
|
||||||
.getOrCreateSelf(db, PhoneUtils.getDefault()
|
.getOrCreateSelf(db, PhoneUtils.getDefault()
|
||||||
@@ -429,9 +395,6 @@ public class ProcessPendingMessagesAction extends Action implements Parcelable {
|
|||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
cursor.close();
|
cursor.close();
|
||||||
}
|
}
|
||||||
if (sending != null) {
|
|
||||||
sending.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
|
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,
|
private static String findNextMessageToDownload(final DatabaseWrapper db, final long now,
|
||||||
final int subId) {
|
final String selfId) {
|
||||||
String toDownloadMessageId = null;
|
String toDownloadMessageId = null;
|
||||||
db.beginTransaction();
|
|
||||||
Cursor cursor = null;
|
Cursor cursor = null;
|
||||||
int downloadingCnt = 0;
|
int downloadingCnt = 0;
|
||||||
int pendingCnt = 0;
|
int pendingCnt = 0;
|
||||||
|
db.beginTransaction();
|
||||||
try {
|
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
|
// First check if we have any messages already downloading
|
||||||
downloadingCnt = (int) db.queryNumEntries(DatabaseHelper.MESSAGES_TABLE
|
downloadingCnt = (int) db.queryNumEntries(DatabaseHelper.MESSAGES_TABLE,
|
||||||
+ "," + DatabaseHelper.PARTICIPANTS_TABLE,
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?) AND "
|
||||||
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?)"
|
+ DatabaseHelper.MessageColumns.SELF_PARTICIPANT_ID + " =?",
|
||||||
+ " AND " + subIdClause,
|
|
||||||
new String[] {
|
new String[] {
|
||||||
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING),
|
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING),
|
||||||
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING),
|
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING),
|
||||||
Integer.toString(subId)
|
selfId
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: This query is not actually needed if downloadingCnt == 0.
|
// TODO: This query is not actually needed if downloadingCnt == 0.
|
||||||
cursor = db.query(DatabaseHelper.MESSAGES_TABLE + ","
|
cursor = db.query(DatabaseHelper.MESSAGES_TABLE,
|
||||||
+ DatabaseHelper.PARTICIPANTS_TABLE,
|
MessageData.getProjection(),
|
||||||
projection,
|
DatabaseHelper.MessageColumns.STATUS + " IN (?, ?) AND "
|
||||||
DatabaseHelper.MessageColumns.STATUS + " =? OR "
|
+ DatabaseHelper.MessageColumns.SELF_PARTICIPANT_ID + " =? ",
|
||||||
+ DatabaseHelper.MessageColumns.STATUS + " =?"
|
|
||||||
+ " AND " + subIdClause,
|
|
||||||
new String[]{
|
new String[]{
|
||||||
Integer.toString(
|
Integer.toString(MessageData.BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD),
|
||||||
MessageData.BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD),
|
|
||||||
Integer.toString(
|
Integer.toString(
|
||||||
MessageData.BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD),
|
MessageData.BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD),
|
||||||
Integer.toString(
|
selfId
|
||||||
subId)
|
|
||||||
},
|
},
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ public class ReceiveSmsMessageAction extends Action implements Parcelable {
|
|||||||
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
|
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
|
||||||
|
|
||||||
private static final String KEY_MESSAGE_VALUES = "message_values";
|
private static final String KEY_MESSAGE_VALUES = "message_values";
|
||||||
|
private static final String KEY_SUB_ID = "sub_id";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a message received from a particular number in a particular conversation
|
* Create a message received from a particular number in a particular conversation
|
||||||
@@ -158,6 +159,7 @@ public class ReceiveSmsMessageAction extends Action implements Parcelable {
|
|||||||
+ " in conversation " + message.getConversationId()
|
+ " in conversation " + message.getConversationId()
|
||||||
+ ", uri = " + messageUri);
|
+ ", uri = " + messageUri);
|
||||||
|
|
||||||
|
actionParameters.putInt(KEY_SUB_ID, subId);
|
||||||
ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(false, this);
|
ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(false, this);
|
||||||
} else {
|
} else {
|
||||||
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
|
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
|
||||||
|
|||||||
@@ -36,7 +36,9 @@ import com.android.messaging.util.LogUtil;
|
|||||||
*/
|
*/
|
||||||
public class RedownloadMmsAction extends Action implements Parcelable {
|
public class RedownloadMmsAction extends Action implements Parcelable {
|
||||||
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
|
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
|
||||||
private static final int REQUEST_CODE_PENDING_INTENT = 102;
|
private static final int REQUEST_CODE_PENDING_INTENT = 101;
|
||||||
|
|
||||||
|
private static final String KEY_SUB_ID = "sub_id";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download an MMS message
|
* Download an MMS message
|
||||||
@@ -90,7 +92,8 @@ public class RedownloadMmsAction extends Action implements Parcelable {
|
|||||||
BugleDatabaseOperations.updateMessageRow(db, message.getMessageId(), values);
|
BugleDatabaseOperations.updateMessageRow(db, message.getMessageId(), values);
|
||||||
|
|
||||||
MessagingContentProvider.notifyMessagesChanged(message.getConversationId());
|
MessagingContentProvider.notifyMessagesChanged(message.getConversationId());
|
||||||
|
actionParameters.putInt(KEY_SUB_ID,
|
||||||
|
BugleDatabaseOperations.getSelfSubscriptionId(db, message.getSelfId()));
|
||||||
// Whether we succeeded or failed we will check and maybe schedule some more work
|
// Whether we succeeded or failed we will check and maybe schedule some more work
|
||||||
ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(false, this);
|
ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(false, this);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ import com.android.messaging.util.LogUtil;
|
|||||||
public class ResendMessageAction extends Action implements Parcelable {
|
public class ResendMessageAction extends Action implements Parcelable {
|
||||||
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
|
private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
|
||||||
|
|
||||||
|
private static final String KEY_SUB_ID = "sub_id";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manual send of existing message (no listener)
|
* Manual send of existing message (no listener)
|
||||||
*/
|
*/
|
||||||
@@ -87,6 +89,9 @@ public class ResendMessageAction extends Action implements Parcelable {
|
|||||||
|
|
||||||
MessagingContentProvider.notifyMessagesChanged(message.getConversationId());
|
MessagingContentProvider.notifyMessagesChanged(message.getConversationId());
|
||||||
|
|
||||||
|
actionParameters.putInt(KEY_SUB_ID,
|
||||||
|
BugleDatabaseOperations.getSelfSubscriptionId(db, message.getSelfId()));
|
||||||
|
|
||||||
// Whether we succeeded or failed we will check and maybe schedule some more work
|
// Whether we succeeded or failed we will check and maybe schedule some more work
|
||||||
ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(false, this);
|
ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(false, this);
|
||||||
|
|
||||||
|
|||||||
@@ -22,10 +22,12 @@ import android.database.Cursor;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
import androidx.appcompat.mms.MmsManager;
|
|
||||||
import android.telephony.SubscriptionInfo;
|
import android.telephony.SubscriptionInfo;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import androidx.appcompat.mms.MmsManager;
|
||||||
|
import androidx.collection.ArrayMap;
|
||||||
|
|
||||||
import com.android.ex.chips.RecipientEntry;
|
import com.android.ex.chips.RecipientEntry;
|
||||||
import com.android.messaging.Factory;
|
import com.android.messaging.Factory;
|
||||||
import com.android.messaging.R;
|
import com.android.messaging.R;
|
||||||
@@ -41,6 +43,10 @@ import com.android.messaging.util.TextUtil;
|
|||||||
* A class that encapsulates all of the data for a specific participant in a conversation.
|
* A class that encapsulates all of the data for a specific participant in a conversation.
|
||||||
*/
|
*/
|
||||||
public class ParticipantData implements Parcelable {
|
public class ParticipantData implements Parcelable {
|
||||||
|
|
||||||
|
private static final ArrayMap<Integer, String> sSubIdtoParticipantIdCache =
|
||||||
|
new ArrayMap<Integer, String>();
|
||||||
|
|
||||||
// We always use -1 as default/invalid sub id although system may give us anything negative
|
// We always use -1 as default/invalid sub id although system may give us anything negative
|
||||||
public static final int DEFAULT_SELF_SUB_ID = MmsManager.DEFAULT_SUB_ID;
|
public static final int DEFAULT_SELF_SUB_ID = MmsManager.DEFAULT_SUB_ID;
|
||||||
|
|
||||||
@@ -282,6 +288,34 @@ public class ParticipantData implements Parcelable {
|
|||||||
return pd;
|
return pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getParticipantId(final DatabaseWrapper db, final int subId) {
|
||||||
|
String id;
|
||||||
|
synchronized (sSubIdtoParticipantIdCache) {
|
||||||
|
id = sSubIdtoParticipantIdCache.get(subId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id != null) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
try (final Cursor cursor =
|
||||||
|
db.query(DatabaseHelper.PARTICIPANTS_TABLE,
|
||||||
|
new String[] {ParticipantColumns._ID},
|
||||||
|
ParticipantColumns.SUB_ID + " =?",
|
||||||
|
new String[] {Integer.toString(subId)}, null, null, null)) {
|
||||||
|
|
||||||
|
if (cursor.moveToFirst()) {
|
||||||
|
// We found an existing participant in the database
|
||||||
|
id = cursor.getString(0);
|
||||||
|
synchronized (sSubIdtoParticipantIdCache) {
|
||||||
|
// Add it to the cache for next time
|
||||||
|
sSubIdtoParticipantIdCache.put(subId, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
private void maybeSetupUnknownSender() {
|
private void maybeSetupUnknownSender() {
|
||||||
if (isUnknownSender()) {
|
if (isUnknownSender()) {
|
||||||
// Because your locale may change, we setup the display string for the unknown sender
|
// Because your locale may change, we setup the display string for the unknown sender
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ import android.database.Cursor;
|
|||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteException;
|
import android.database.sqlite.SQLiteException;
|
||||||
import android.media.MediaMetadataRetriever;
|
import android.media.MediaMetadataRetriever;
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
@@ -2661,26 +2659,6 @@ public class MmsUtils {
|
|||||||
return stringResId;
|
return stringResId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The absence of a connection type.
|
|
||||||
*/
|
|
||||||
public static final int TYPE_NONE = -1;
|
|
||||||
|
|
||||||
public static int getConnectivityEventNetworkType(final Context context, final Intent intent) {
|
|
||||||
final ConnectivityManager connMgr = (ConnectivityManager)
|
|
||||||
context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
|
||||||
if (OsUtil.isAtLeastJB_MR1()) {
|
|
||||||
return intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, TYPE_NONE);
|
|
||||||
} else {
|
|
||||||
final NetworkInfo info = (NetworkInfo) intent.getParcelableExtra(
|
|
||||||
ConnectivityManager.EXTRA_NETWORK_INFO);
|
|
||||||
if (info != null) {
|
|
||||||
return info.getType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return TYPE_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dump the raw MMS data into a file
|
* Dump the raw MMS data into a file
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -66,6 +66,6 @@ public final class BuglePrefsKeys {
|
|||||||
* The attempt number when retrying ProcessPendingMessagesAction
|
* The attempt number when retrying ProcessPendingMessagesAction
|
||||||
*/
|
*/
|
||||||
public static final String PROCESS_PENDING_MESSAGES_RETRY_COUNT
|
public static final String PROCESS_PENDING_MESSAGES_RETRY_COUNT
|
||||||
= "process_pending_retry";
|
= BuglePrefs.SHARED_PREFERENCES_PER_SUBSCRIPTION_PREFIX + "process_pending_retry";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,40 +16,33 @@
|
|||||||
|
|
||||||
package com.android.messaging.util;
|
package com.android.messaging.util;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.telephony.PhoneStateListener;
|
import android.telephony.PhoneStateListener;
|
||||||
import android.telephony.ServiceState;
|
import android.telephony.ServiceState;
|
||||||
import android.telephony.SignalStrength;
|
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
|
|
||||||
|
import com.android.messaging.datamodel.data.ParticipantData;
|
||||||
|
|
||||||
public class ConnectivityUtil {
|
public class ConnectivityUtil {
|
||||||
// Assume not connected until informed differently
|
// Assume not connected until informed differently
|
||||||
private volatile int mCurrentServiceState = ServiceState.STATE_POWER_OFF;
|
private volatile int mCurrentServiceState = ServiceState.STATE_POWER_OFF;
|
||||||
|
|
||||||
private final TelephonyManager mTelephonyManager;
|
private final TelephonyManager mTelephonyManager;
|
||||||
private final Context mContext;
|
|
||||||
private final ConnectivityBroadcastReceiver mReceiver;
|
|
||||||
private final ConnectivityManager mConnMgr;
|
|
||||||
|
|
||||||
private ConnectivityListener mListener;
|
private ConnectivityListener mListener;
|
||||||
private final IntentFilter mIntentFilter;
|
|
||||||
|
|
||||||
public interface ConnectivityListener {
|
public interface ConnectivityListener {
|
||||||
public void onConnectivityStateChanged(final Context context, final Intent intent);
|
public void onPhoneStateChanged(int serviceState);
|
||||||
public void onPhoneStateChanged(final Context context, int serviceState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConnectivityUtil(final Context context) {
|
public ConnectivityUtil(final Context context) {
|
||||||
mContext = context;
|
|
||||||
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
}
|
||||||
mReceiver = new ConnectivityBroadcastReceiver();
|
|
||||||
mIntentFilter = new IntentFilter();
|
public ConnectivityUtil(final Context context, final int subId) {
|
||||||
mIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
mTelephonyManager =
|
||||||
|
((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE))
|
||||||
|
.createForSubscriptionId(subId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCurrentServiceState() {
|
public int getCurrentServiceState() {
|
||||||
@@ -75,14 +68,7 @@ public class ConnectivityUtil {
|
|||||||
private void onPhoneStateChanged(final int serviceState) {
|
private void onPhoneStateChanged(final int serviceState) {
|
||||||
final ConnectivityListener listener = mListener;
|
final ConnectivityListener listener = mListener;
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.onPhoneStateChanged(mContext, serviceState);
|
listener.onPhoneStateChanged(serviceState);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onConnectivityChanged(final Context context, final Intent intent) {
|
|
||||||
final ConnectivityListener listener = mListener;
|
|
||||||
if (listener != null) {
|
|
||||||
listener.onConnectivityStateChanged(context, intent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,9 +81,6 @@ public class ConnectivityUtil {
|
|||||||
mTelephonyManager.listen(mPhoneStateListener,
|
mTelephonyManager.listen(mPhoneStateListener,
|
||||||
PhoneStateListener.LISTEN_SERVICE_STATE);
|
PhoneStateListener.LISTEN_SERVICE_STATE);
|
||||||
}
|
}
|
||||||
if (mConnMgr != null) {
|
|
||||||
mContext.registerReceiver(mReceiver, mIntentFilter);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
}
|
}
|
||||||
@@ -108,140 +91,7 @@ public class ConnectivityUtil {
|
|||||||
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
|
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
|
||||||
mCurrentServiceState = ServiceState.STATE_POWER_OFF;
|
mCurrentServiceState = ServiceState.STATE_POWER_OFF;
|
||||||
}
|
}
|
||||||
if (mConnMgr != null) {
|
|
||||||
mContext.unregisterReceiver(mReceiver);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
mListener = null;
|
mListener = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Connectivity change broadcast receiver. This gets the network connectivity updates.
|
|
||||||
* In case we don't get the active connectivity when we first acquire the network,
|
|
||||||
* this receiver will notify us when it is connected, so to unblock the waiting thread
|
|
||||||
* which is sending the message.
|
|
||||||
*/
|
|
||||||
public class ConnectivityBroadcastReceiver extends BroadcastReceiver {
|
|
||||||
@Override
|
|
||||||
public void onReceive(final Context context, final Intent intent) {
|
|
||||||
if (!intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
onConnectivityChanged(context, intent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int mSignalLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
|
|
||||||
|
|
||||||
// We use a separate instance than mPhoneStateListener because the lifetimes are different.
|
|
||||||
private final PhoneStateListener mSignalStrengthListener = new PhoneStateListener() {
|
|
||||||
@Override
|
|
||||||
public void onSignalStrengthsChanged(final SignalStrength signalStrength) {
|
|
||||||
mSignalLevel = getLevel(signalStrength);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public void registerForSignalStrength() {
|
|
||||||
mTelephonyManager.listen(
|
|
||||||
mSignalStrengthListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregisterForSignalStrength() {
|
|
||||||
mTelephonyManager.listen(mSignalStrengthListener, PhoneStateListener.LISTEN_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param subId This is ignored because TelephonyManager does not support it.
|
|
||||||
* @return Signal strength as level 0..4
|
|
||||||
*/
|
|
||||||
public int getSignalLevel(final int subId) {
|
|
||||||
return mSignalLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int SIGNAL_STRENGTH_NONE_OR_UNKNOWN = 0;
|
|
||||||
private static final int SIGNAL_STRENGTH_POOR = 1;
|
|
||||||
private static final int SIGNAL_STRENGTH_MODERATE = 2;
|
|
||||||
private static final int SIGNAL_STRENGTH_GOOD = 3;
|
|
||||||
private static final int SIGNAL_STRENGTH_GREAT = 4;
|
|
||||||
|
|
||||||
private static final int GSM_SIGNAL_STRENGTH_GREAT = 12;
|
|
||||||
private static final int GSM_SIGNAL_STRENGTH_GOOD = 8;
|
|
||||||
private static final int GSM_SIGNAL_STRENGTH_MODERATE = 8;
|
|
||||||
|
|
||||||
private static int getLevel(final SignalStrength signalStrength) {
|
|
||||||
if (signalStrength.isGsm()) {
|
|
||||||
// From frameworks/base/telephony/java/android/telephony/CellSignalStrengthGsm.java
|
|
||||||
|
|
||||||
// ASU ranges from 0 to 31 - TS 27.007 Sec 8.5
|
|
||||||
// asu = 0 (-113dB or less) is very weak
|
|
||||||
// signal, its better to show 0 bars to the user in such cases.
|
|
||||||
// asu = 99 is a special case, where the signal strength is unknown.
|
|
||||||
final int asu = signalStrength.getGsmSignalStrength();
|
|
||||||
if (asu <= 2 || asu == 99) return SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
|
|
||||||
else if (asu >= GSM_SIGNAL_STRENGTH_GREAT) return SIGNAL_STRENGTH_GREAT;
|
|
||||||
else if (asu >= GSM_SIGNAL_STRENGTH_GOOD) return SIGNAL_STRENGTH_GOOD;
|
|
||||||
else if (asu >= GSM_SIGNAL_STRENGTH_MODERATE) return SIGNAL_STRENGTH_MODERATE;
|
|
||||||
else return SIGNAL_STRENGTH_POOR;
|
|
||||||
} else {
|
|
||||||
// From frameworks/base/telephony/java/android/telephony/CellSignalStrengthCdma.java
|
|
||||||
|
|
||||||
final int cdmaLevel = getCdmaLevel(signalStrength);
|
|
||||||
final int evdoLevel = getEvdoLevel(signalStrength);
|
|
||||||
if (evdoLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
|
|
||||||
/* We don't know evdo, use cdma */
|
|
||||||
return getCdmaLevel(signalStrength);
|
|
||||||
} else if (cdmaLevel == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
|
|
||||||
/* We don't know cdma, use evdo */
|
|
||||||
return getEvdoLevel(signalStrength);
|
|
||||||
} else {
|
|
||||||
/* We know both, use the lowest level */
|
|
||||||
return cdmaLevel < evdoLevel ? cdmaLevel : evdoLevel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get cdma as level 0..4
|
|
||||||
*/
|
|
||||||
private static int getCdmaLevel(final SignalStrength signalStrength) {
|
|
||||||
final int cdmaDbm = signalStrength.getCdmaDbm();
|
|
||||||
final int cdmaEcio = signalStrength.getCdmaEcio();
|
|
||||||
int levelDbm;
|
|
||||||
int levelEcio;
|
|
||||||
if (cdmaDbm >= -75) levelDbm = SIGNAL_STRENGTH_GREAT;
|
|
||||||
else if (cdmaDbm >= -85) levelDbm = SIGNAL_STRENGTH_GOOD;
|
|
||||||
else if (cdmaDbm >= -95) levelDbm = SIGNAL_STRENGTH_MODERATE;
|
|
||||||
else if (cdmaDbm >= -100) levelDbm = SIGNAL_STRENGTH_POOR;
|
|
||||||
else levelDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
|
|
||||||
// Ec/Io are in dB*10
|
|
||||||
if (cdmaEcio >= -90) levelEcio = SIGNAL_STRENGTH_GREAT;
|
|
||||||
else if (cdmaEcio >= -110) levelEcio = SIGNAL_STRENGTH_GOOD;
|
|
||||||
else if (cdmaEcio >= -130) levelEcio = SIGNAL_STRENGTH_MODERATE;
|
|
||||||
else if (cdmaEcio >= -150) levelEcio = SIGNAL_STRENGTH_POOR;
|
|
||||||
else levelEcio = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
|
|
||||||
final int level = (levelDbm < levelEcio) ? levelDbm : levelEcio;
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Get Evdo as level 0..4
|
|
||||||
*/
|
|
||||||
private static int getEvdoLevel(final SignalStrength signalStrength) {
|
|
||||||
final int evdoDbm = signalStrength.getEvdoDbm();
|
|
||||||
final int evdoSnr = signalStrength.getEvdoSnr();
|
|
||||||
int levelEvdoDbm;
|
|
||||||
int levelEvdoSnr;
|
|
||||||
if (evdoDbm >= -65) levelEvdoDbm = SIGNAL_STRENGTH_GREAT;
|
|
||||||
else if (evdoDbm >= -75) levelEvdoDbm = SIGNAL_STRENGTH_GOOD;
|
|
||||||
else if (evdoDbm >= -90) levelEvdoDbm = SIGNAL_STRENGTH_MODERATE;
|
|
||||||
else if (evdoDbm >= -105) levelEvdoDbm = SIGNAL_STRENGTH_POOR;
|
|
||||||
else levelEvdoDbm = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
|
|
||||||
if (evdoSnr >= 7) levelEvdoSnr = SIGNAL_STRENGTH_GREAT;
|
|
||||||
else if (evdoSnr >= 5) levelEvdoSnr = SIGNAL_STRENGTH_GOOD;
|
|
||||||
else if (evdoSnr >= 3) levelEvdoSnr = SIGNAL_STRENGTH_MODERATE;
|
|
||||||
else if (evdoSnr >= 1) levelEvdoSnr = SIGNAL_STRENGTH_POOR;
|
|
||||||
else levelEvdoSnr = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
|
|
||||||
final int level = (levelEvdoDbm < levelEvdoSnr) ? levelEvdoDbm : levelEvdoSnr;
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import org.mockito.Mockito;
|
|||||||
import org.mockito.invocation.InvocationOnMock;
|
import org.mockito.invocation.InvocationOnMock;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class FakeFactory extends Factory {
|
public class FakeFactory extends Factory {
|
||||||
@@ -121,7 +122,8 @@ public class FakeFactory extends Factory {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
|
public List<SubscriptionInfo> getActiveSubscriptionInfoList() {
|
||||||
return null;
|
// Return empty list
|
||||||
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -36,9 +36,9 @@ public class DataModelTest extends BugleTestCase {
|
|||||||
@Override
|
@Override
|
||||||
protected void setUp() throws Exception {
|
protected void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
|
FakeFactory factory = FakeFactory.register(mContext);
|
||||||
dataModel = new DataModelImpl(getTestContext());
|
dataModel = new DataModelImpl(getTestContext());
|
||||||
FakeFactory.register(mContext)
|
factory.withDataModel(dataModel);
|
||||||
.withDataModel(dataModel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ import com.android.messaging.datamodel.data.SettingsData.SettingsDataListener;
|
|||||||
import com.android.messaging.datamodel.data.SubscriptionListData;
|
import com.android.messaging.datamodel.data.SubscriptionListData;
|
||||||
import com.android.messaging.datamodel.data.TestDataFactory;
|
import com.android.messaging.datamodel.data.TestDataFactory;
|
||||||
import com.android.messaging.datamodel.data.VCardContactItemData;
|
import com.android.messaging.datamodel.data.VCardContactItemData;
|
||||||
import com.android.messaging.util.ConnectivityUtil;
|
|
||||||
|
|
||||||
public class FakeDataModel extends DataModel {
|
public class FakeDataModel extends DataModel {
|
||||||
private BackgroundWorker mWorker;
|
private BackgroundWorker mWorker;
|
||||||
@@ -58,7 +57,6 @@ public class FakeDataModel extends DataModel {
|
|||||||
private ContactPickerData mContactPickerData;
|
private ContactPickerData mContactPickerData;
|
||||||
private MediaPickerData mMediaPickerData;
|
private MediaPickerData mMediaPickerData;
|
||||||
private PeopleAndOptionsData mPeopleAndOptionsData;
|
private PeopleAndOptionsData mPeopleAndOptionsData;
|
||||||
private ConnectivityUtil mConnectivityUtil;
|
|
||||||
private SyncManager mSyncManager;
|
private SyncManager mSyncManager;
|
||||||
private SettingsData mSettingsData;
|
private SettingsData mSettingsData;
|
||||||
private DraftMessageData mDraftMessageData;
|
private DraftMessageData mDraftMessageData;
|
||||||
@@ -102,11 +100,6 @@ public class FakeDataModel extends DataModel {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FakeDataModel withConnectivityUtil(final ConnectivityUtil connectivityUtil) {
|
|
||||||
mConnectivityUtil = connectivityUtil;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FakeDataModel withSyncManager(final SyncManager syncManager) {
|
public FakeDataModel withSyncManager(final SyncManager syncManager) {
|
||||||
mSyncManager = syncManager;
|
mSyncManager = syncManager;
|
||||||
return this;
|
return this;
|
||||||
@@ -219,11 +212,6 @@ public class FakeDataModel extends DataModel {
|
|||||||
return mActionService;
|
return mActionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ConnectivityUtil getConnectivityUtil() {
|
|
||||||
return mConnectivityUtil;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SyncManager getSyncManager() {
|
public SyncManager getSyncManager() {
|
||||||
return mSyncManager;
|
return mSyncManager;
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import com.android.messaging.datamodel.action.ActionMonitor.ActionCompletedListe
|
|||||||
import com.android.messaging.datamodel.action.ActionMonitor.ActionExecutedListener;
|
import com.android.messaging.datamodel.action.ActionMonitor.ActionExecutedListener;
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.ResultTracker;
|
import com.android.messaging.datamodel.action.ActionTestHelpers.ResultTracker;
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubBackgroundWorker;
|
import com.android.messaging.datamodel.action.ActionTestHelpers.StubBackgroundWorker;
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubConnectivityUtil;
|
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubLoader;
|
import com.android.messaging.datamodel.action.ActionTestHelpers.StubLoader;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -291,8 +290,7 @@ public class ActionServiceSystemTest extends BugleServiceTestCase<ActionServiceI
|
|||||||
FakeFactory.registerWithFakeContext(getContext(), mContext)
|
FakeFactory.registerWithFakeContext(getContext(), mContext)
|
||||||
.withDataModel(new FakeDataModel(mContext)
|
.withDataModel(new FakeDataModel(mContext)
|
||||||
.withBackgroundWorkerForActionService(mWorker)
|
.withBackgroundWorkerForActionService(mWorker)
|
||||||
.withActionService(new ActionService())
|
.withActionService(new ActionService()));
|
||||||
.withConnectivityUtil(new StubConnectivityUtil(mContext)));
|
|
||||||
|
|
||||||
mLoader = new StubLoader();
|
mLoader = new StubLoader();
|
||||||
setContext(Factory.get().getApplicationContext());
|
setContext(Factory.get().getApplicationContext());
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ import com.android.messaging.datamodel.action.ActionMonitor.ActionCompletedListe
|
|||||||
import com.android.messaging.datamodel.action.ActionMonitor.ActionStateChangedListener;
|
import com.android.messaging.datamodel.action.ActionMonitor.ActionStateChangedListener;
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.ResultTracker;
|
import com.android.messaging.datamodel.action.ActionTestHelpers.ResultTracker;
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubBackgroundWorker;
|
import com.android.messaging.datamodel.action.ActionTestHelpers.StubBackgroundWorker;
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubConnectivityUtil;
|
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubLoader;
|
import com.android.messaging.datamodel.action.ActionTestHelpers.StubLoader;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -145,8 +144,7 @@ public class ActionServiceTest extends BugleServiceTestCase<ActionServiceImpl>
|
|||||||
FakeFactory.registerWithFakeContext(getContext(),mContext)
|
FakeFactory.registerWithFakeContext(getContext(),mContext)
|
||||||
.withDataModel(new FakeDataModel(mContext)
|
.withDataModel(new FakeDataModel(mContext)
|
||||||
.withBackgroundWorkerForActionService(mWorker)
|
.withBackgroundWorkerForActionService(mWorker)
|
||||||
.withActionService(new ActionService())
|
.withActionService(new ActionService()));
|
||||||
.withConnectivityUtil(new StubConnectivityUtil(mContext)));
|
|
||||||
|
|
||||||
mStates = new ArrayList<Integer>();
|
mStates = new ArrayList<Integer>();
|
||||||
setContext(Factory.get().getApplicationContext());
|
setContext(Factory.get().getApplicationContext());
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ import android.database.ContentObserver;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import com.android.messaging.util.ConnectivityUtil;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -174,18 +172,4 @@ public class ActionTestHelpers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StubConnectivityUtil extends ConnectivityUtil {
|
|
||||||
public StubConnectivityUtil(final Context context) {
|
|
||||||
super(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void registerForSignalStrength() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unregisterForSignalStrength() {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -36,7 +36,6 @@ import com.android.messaging.datamodel.MediaScratchFileProvider;
|
|||||||
import com.android.messaging.datamodel.MessagingContentProvider;
|
import com.android.messaging.datamodel.MessagingContentProvider;
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService;
|
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService;
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService.StubActionServiceCallLog;
|
import com.android.messaging.datamodel.action.ActionTestHelpers.StubActionService.StubActionServiceCallLog;
|
||||||
import com.android.messaging.datamodel.action.ActionTestHelpers.StubConnectivityUtil;
|
|
||||||
import com.android.messaging.datamodel.action.ReadDraftDataAction.ReadDraftDataActionListener;
|
import com.android.messaging.datamodel.action.ReadDraftDataAction.ReadDraftDataActionListener;
|
||||||
import com.android.messaging.datamodel.data.MessageData;
|
import com.android.messaging.datamodel.data.MessageData;
|
||||||
import com.android.messaging.datamodel.data.MessagePartData;
|
import com.android.messaging.datamodel.data.MessagePartData;
|
||||||
@@ -473,8 +472,7 @@ public class ReadWriteDraftMessageActionTest extends BugleTestCase {
|
|||||||
|
|
||||||
mService = new StubActionService();
|
mService = new StubActionService();
|
||||||
final FakeDataModel fakeDataModel = new FakeDataModel(context)
|
final FakeDataModel fakeDataModel = new FakeDataModel(context)
|
||||||
.withActionService(mService)
|
.withActionService(mService);
|
||||||
.withConnectivityUtil(new StubConnectivityUtil(context));
|
|
||||||
FakeFactory.registerWithFakeContext(getTestContext(), context)
|
FakeFactory.registerWithFakeContext(getTestContext(), context)
|
||||||
.withDataModel(fakeDataModel);
|
.withDataModel(fakeDataModel);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user