am 979749e8: am 5de694a2: am a04cf879: am f4909bf3: am 5a726879: am 9da13d25: Externally Reported Low Severity Security Vulnerability: SMS Resend Vulnerability in Android
* commit '979749e84490cab29c0ba9c5e3fb08fa6beb9fbd':
Externally Reported Low Severity Security Vulnerability: SMS Resend Vulnerability in Android
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 482705e..bfe46ff 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -197,6 +197,9 @@
<action android:name="android.intent.action.CONTENT_CHANGED" />
</intent-filter>
<intent-filter>
+ <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
+ </intent-filter>
+ <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
diff --git a/src/com/android/mms/MmsApp.java b/src/com/android/mms/MmsApp.java
index 74f4043..9092a29 100644
--- a/src/com/android/mms/MmsApp.java
+++ b/src/com/android/mms/MmsApp.java
@@ -19,6 +19,7 @@
import android.app.Application;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
import android.drm.DrmManagerClient;
import android.location.Country;
@@ -34,6 +35,9 @@
import com.android.mms.data.Conversation;
import com.android.mms.layout.LayoutManager;
import com.android.mms.transaction.MessagingNotification;
+import com.android.mms.transaction.MmsSystemEventReceiver;
+import com.android.mms.transaction.SmsReceiver;
+import com.android.mms.transaction.SmsReceiverService;
import com.android.mms.util.DownloadManager;
import com.android.mms.util.DraftCache;
import com.android.mms.util.PduLoaderManager;
@@ -94,6 +98,23 @@
LayoutManager.init(this);
SmileyParser.init(this);
MessagingNotification.init(this);
+
+ activePendingMessages();
+ }
+
+ /**
+ * Try to process all pending messages(which were interrupted by user, OOM, Mms crashing,
+ * etc...) when Mms app is (re)launched.
+ */
+ private void activePendingMessages() {
+ // For Mms: try to process all pending transactions if possible
+ MmsSystemEventReceiver.wakeUpService(this);
+
+ // For Sms: retry to send smses in outbox and queued box
+ sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_INACTIVE_MESSAGE,
+ null,
+ this,
+ SmsReceiver.class));
}
synchronized public static MmsApp getApplication() {
diff --git a/src/com/android/mms/data/Conversation.java b/src/com/android/mms/data/Conversation.java
index 91bea24..106cea2 100644
--- a/src/com/android/mms/data/Conversation.java
+++ b/src/com/android/mms/data/Conversation.java
@@ -13,6 +13,7 @@
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.database.sqlite.SqliteWrapper;
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.BaseColumns;
@@ -30,10 +31,14 @@
import com.android.mms.MmsApp;
import com.android.mms.R;
import com.android.mms.transaction.MessagingNotification;
+import com.android.mms.transaction.MmsMessageSender;
import com.android.mms.ui.ComposeMessageActivity;
import com.android.mms.ui.MessageUtils;
+import com.android.mms.util.AddressUtils;
import com.android.mms.util.DraftCache;
+import com.google.android.mms.pdu.PduHeaders;
+
/**
* An interface for finding information about conversations and/or creating new ones.
*/
@@ -297,6 +302,42 @@
}
}
+ private void sendReadReport(final Context context,
+ final long threadId,
+ final int status) {
+ String selection = Mms.MESSAGE_TYPE + " = " + PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF
+ + " AND " + Mms.READ + " = 0"
+ + " AND " + Mms.READ_REPORT + " = " + PduHeaders.VALUE_YES;
+
+ if (threadId != -1) {
+ selection = selection + " AND " + Mms.THREAD_ID + " = " + threadId;
+ }
+
+ final Cursor c = SqliteWrapper.query(context, context.getContentResolver(),
+ Mms.Inbox.CONTENT_URI, new String[] {Mms._ID, Mms.MESSAGE_ID},
+ selection, null, null);
+
+ try {
+ if (c == null || c.getCount() == 0) {
+ return;
+ }
+
+ while (c.moveToNext()) {
+ Uri uri = ContentUris.withAppendedId(Mms.CONTENT_URI, c.getLong(0));
+ if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
+ LogTag.debug("sendReadReport: uri = " + uri);
+ }
+ MmsMessageSender.sendReadRec(context, AddressUtils.getFrom(context, uri),
+ c.getString(1), status);
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+
/**
* Marks all messages in this conversation as read and updates
* relevant notifications. This method returns immediately;
@@ -347,6 +388,7 @@
}
if (needUpdate) {
+ sendReadReport(mContext, mThreadId, PduHeaders.READ_STATUS_READ);
LogTag.debug("markAsRead: update read/seen for thread uri: " +
threadUri);
mContext.getContentResolver().update(threadUri, sReadContentValues,
diff --git a/src/com/android/mms/model/LayoutModel.java b/src/com/android/mms/model/LayoutModel.java
index 97b1637..0280534 100644
--- a/src/com/android/mms/model/LayoutModel.java
+++ b/src/com/android/mms/model/LayoutModel.java
@@ -110,6 +110,11 @@
if (mTextRegion == null) {
createDefaultTextRegion();
}
+ // LayoutModel will re-construct when orientation changes, so we need to
+ // initialize mLayoutType here. Otherwise, the mLayoutType is alway default
+ // value (LAYOUT_BOTTOM_TEXT) after LayoutModel re-construct.
+ mLayoutType =
+ (mImageRegion.getTop() == 0) ? LAYOUT_BOTTOM_TEXT : LAYOUT_TOP_TEXT;
}
public RegionModel getRootLayout() {
diff --git a/src/com/android/mms/model/VideoModel.java b/src/com/android/mms/model/VideoModel.java
index a426b42..a71e455 100644
--- a/src/com/android/mms/model/VideoModel.java
+++ b/src/com/android/mms/model/VideoModel.java
@@ -70,7 +70,8 @@
}
private void initFromFile(Uri uri) {
- mSrc = uri.getPath();
+ String path = uri.getPath();
+ mSrc = path.substring(path.lastIndexOf('/') + 1);
MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
String extension = MimeTypeMap.getFileExtensionFromUrl(mSrc);
if (TextUtils.isEmpty(extension)) {
diff --git a/src/com/android/mms/transaction/MmsSystemEventReceiver.java b/src/com/android/mms/transaction/MmsSystemEventReceiver.java
index b8eb917..9b78ea0 100644
--- a/src/com/android/mms/transaction/MmsSystemEventReceiver.java
+++ b/src/com/android/mms/transaction/MmsSystemEventReceiver.java
@@ -20,13 +20,12 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.net.Uri;
import android.provider.Telephony.Mms;
import android.util.Log;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
import com.android.mms.LogTag;
import com.android.mms.MmsApp;
@@ -43,9 +42,9 @@
*/
public class MmsSystemEventReceiver extends BroadcastReceiver {
private static final String TAG = "MmsSystemEventReceiver";
- private static MmsSystemEventReceiver sMmsSystemEventReceiver;
+ private static ConnectivityManager mConnMgr = null;
- private static void wakeUpService(Context context) {
+ public static void wakeUpService(Context context) {
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
Log.v(TAG, "wakeUpService: start transaction service ...");
}
@@ -63,14 +62,23 @@
if (action.equals(Mms.Intents.CONTENT_CHANGED_ACTION)) {
Uri changed = (Uri) intent.getParcelableExtra(Mms.Intents.DELETED_CONTENTS);
MmsApp.getApplication().getPduLoaderManager().removePdu(changed);
- } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) {
- String state = intent.getStringExtra(PhoneConstants.STATE_KEY);
+ } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ if (mConnMgr == null) {
+ mConnMgr = (ConnectivityManager) context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+ NetworkInfo mmsNetworkInfo = mConnMgr
+ .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_MMS);
+ boolean available = mmsNetworkInfo.isAvailable();
+ boolean isConnected = mmsNetworkInfo.isConnected();
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
- Log.v(TAG, "ANY_DATA_STATE event received: " + state);
+ Log.v(TAG, "TYPE_MOBILE_MMS available = " + available +
+ ", isConnected = " + isConnected);
}
- if (state.equals("CONNECTED")) {
+ // Wake up transact service when MMS data is available and isn't connected.
+ if (available && !isConnected) {
wakeUpService(context);
}
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
@@ -79,34 +87,10 @@
// Called on the UI thread so don't block.
MessagingNotification.nonBlockingUpdateNewMessageIndicator(
context, MessagingNotification.THREAD_NONE, false);
- }
- }
- public static void registerForConnectionStateChanges(Context context) {
- unRegisterForConnectionStateChanges(context);
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
- if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
- Log.v(TAG, "registerForConnectionStateChanges");
- }
- if (sMmsSystemEventReceiver == null) {
- sMmsSystemEventReceiver = new MmsSystemEventReceiver();
- }
-
- context.registerReceiver(sMmsSystemEventReceiver, intentFilter);
- }
-
- public static void unRegisterForConnectionStateChanges(Context context) {
- if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
- Log.v(TAG, "unRegisterForConnectionStateChanges");
- }
- if (sMmsSystemEventReceiver != null) {
- try {
- context.unregisterReceiver(sMmsSystemEventReceiver);
- } catch (IllegalArgumentException e) {
- // Allow un-matched register-unregister calls
- }
+ // Scan and send pending Mms once after boot completed since
+ // ACTION_ANY_DATA_CONNECTION_STATE_CHANGED wasn't registered in a whole life cycle
+ wakeUpService(context);
}
}
}
diff --git a/src/com/android/mms/transaction/ReadRecTransaction.java b/src/com/android/mms/transaction/ReadRecTransaction.java
index d424860..bcbfa62 100644
--- a/src/com/android/mms/transaction/ReadRecTransaction.java
+++ b/src/com/android/mms/transaction/ReadRecTransaction.java
@@ -42,11 +42,12 @@
* <li>Notifies the TransactionService about succesful completion.
* </ul>
*/
-public class ReadRecTransaction extends Transaction {
+public class ReadRecTransaction extends Transaction implements Runnable{
private static final String TAG = "ReadRecTransaction";
private static final boolean DEBUG = false;
private static final boolean LOCAL_LOGV = false;
+ private Thread mThread;
private final Uri mReadReportURI;
public ReadRecTransaction(Context context,
@@ -67,6 +68,11 @@
*/
@Override
public void process() {
+ mThread = new Thread(this, "ReadRecTransaction");
+ mThread.start();
+ }
+
+ public void run() {
PduPersister persister = PduPersister.getPduPersister(mContext);
try {
diff --git a/src/com/android/mms/transaction/SmsReceiverService.java b/src/com/android/mms/transaction/SmsReceiverService.java
index 724e863..4985edf 100755
--- a/src/com/android/mms/transaction/SmsReceiverService.java
+++ b/src/com/android/mms/transaction/SmsReceiverService.java
@@ -81,7 +81,9 @@
public static final String EXTRA_MESSAGE_SENT_SEND_NEXT ="SendNextMsg";
public static final String ACTION_SEND_MESSAGE =
- "com.android.mms.transaction.SEND_MESSAGE";
+ "com.android.mms.transaction.SEND_MESSAGE";
+ public static final String ACTION_SEND_INACTIVE_MESSAGE =
+ "com.android.mms.transaction.SEND_INACTIVE_MESSAGE";
// This must match the column IDs below.
private static final String[] SEND_PROJECTION = new String[] {
@@ -209,6 +211,8 @@
handleServiceStateChanged(intent);
} else if (ACTION_SEND_MESSAGE.endsWith(action)) {
handleSendMessage();
+ } else if (ACTION_SEND_INACTIVE_MESSAGE.equals(action)) {
+ handleSendInactiveMessage();
}
}
// NOTE: We MUST not call stopSelf() directly, since we need to
@@ -231,6 +235,12 @@
}
}
+ private void handleSendInactiveMessage() {
+ // Inactive messages includes all messages in outbox and queued box.
+ moveOutboxMessagesToQueuedBox();
+ sendFirstQueuedMessage();
+ }
+
public synchronized void sendFirstQueuedMessage() {
boolean success = true;
// get all the queued messages from the database
@@ -272,6 +282,12 @@
mSending = false;
messageFailedToSend(msgUri, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
success = false;
+ // Sending current message fails. Try to send more pending messages
+ // if there is any.
+ sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
+ null,
+ this,
+ SmsReceiver.class));
}
}
} finally {
@@ -388,6 +404,24 @@
}
/**
+ * Move all messages that are in the outbox to the queued state
+ * @return The number of messages that were actually moved
+ */
+ private int moveOutboxMessagesToQueuedBox() {
+ ContentValues values = new ContentValues(1);
+
+ values.put(Sms.TYPE, Sms.MESSAGE_TYPE_QUEUED);
+
+ int messageCount = SqliteWrapper.update(
+ getApplicationContext(), getContentResolver(), Outbox.CONTENT_URI,
+ values, "type = " + Sms.MESSAGE_TYPE_OUTBOX, null);
+ if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE) || LogTag.DEBUG_SEND) {
+ Log.v(TAG, "moveOutboxMessagesToQueuedBox messageCount: " + messageCount);
+ }
+ return messageCount;
+ }
+
+ /**
* Move all messages that are in the outbox to the failed state and set them to unread.
* @return The number of messages that were actually moved
*/
diff --git a/src/com/android/mms/transaction/TransactionBundle.java b/src/com/android/mms/transaction/TransactionBundle.java
index 5962b90..ea3edc0 100644
--- a/src/com/android/mms/transaction/TransactionBundle.java
+++ b/src/com/android/mms/transaction/TransactionBundle.java
@@ -19,7 +19,7 @@
import android.os.Bundle;
-import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.uicc.IccUtils;
/**
* A wrapper around the Bundle instances used to start the TransactionService.
diff --git a/src/com/android/mms/transaction/TransactionService.java b/src/com/android/mms/transaction/TransactionService.java
index 7fd2715..3de1f71 100644
--- a/src/com/android/mms/transaction/TransactionService.java
+++ b/src/com/android/mms/transaction/TransactionService.java
@@ -229,15 +229,6 @@
int columnIndexOfMsgType = cursor.getColumnIndexOrThrow(
PendingMessages.MSG_TYPE);
- if (noNetwork) {
- // Make sure we register for connection state changes.
- if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
- Log.v(TAG, "onNewIntent: registerForConnectionStateChanges");
- }
- MmsSystemEventReceiver.registerForConnectionStateChanges(
- getApplicationContext());
- }
-
while (cursor.moveToNext()) {
int msgType = cursor.getInt(columnIndexOfMsgType);
int transactionType = getTransactionType(msgType);
@@ -299,11 +290,6 @@
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
Log.v(TAG, "stopSelfIfIdle: STOP!");
}
- // Make sure we're no longer listening for connection state changes.
- if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
- Log.v(TAG, "stopSelfIfIdle: unRegisterForConnectionStateChanges");
- }
- MmsSystemEventReceiver.unRegisterForConnectionStateChanges(getApplicationContext());
stopSelf(startId);
}
@@ -315,8 +301,12 @@
}
private boolean isNetworkAvailable() {
- NetworkInfo ni = mConnMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_MMS);
- return (ni == null ? false : ni.isAvailable());
+ if (mConnMgr == null) {
+ return false;
+ } else {
+ NetworkInfo ni = mConnMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_MMS);
+ return (ni == null ? false : ni.isAvailable());
+ }
}
private int getTransactionType(int msgType) {
@@ -469,7 +459,6 @@
sendBroadcast(intent);
} finally {
transaction.detach(this);
- MmsSystemEventReceiver.unRegisterForConnectionStateChanges(getApplicationContext());
stopSelf(serviceId);
}
}
@@ -881,11 +870,15 @@
return;
}
- boolean noConnectivity =
- intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
+ NetworkInfo mmsNetworkInfo = null;
- NetworkInfo networkInfo = (NetworkInfo)
- intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
+ if (mConnMgr != null) {
+ mmsNetworkInfo = mConnMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_MMS);
+ } else {
+ if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
+ Log.v(TAG, "mConnMgr is null, bail");
+ }
+ }
/*
* If we are being informed that connectivity has been established
@@ -894,47 +887,50 @@
*/
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
- Log.v(TAG, "Handle ConnectivityBroadcastReceiver.onReceive(): " + networkInfo);
+ Log.v(TAG, "Handle ConnectivityBroadcastReceiver.onReceive(): " + mmsNetworkInfo);
}
// Check availability of the mobile network.
- if ((networkInfo == null) || (networkInfo.getType() !=
- ConnectivityManager.TYPE_MOBILE_MMS)) {
+ if ((mmsNetworkInfo == null)) {
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
- Log.v(TAG, " type is not TYPE_MOBILE_MMS, bail");
+ Log.v(TAG, "mms type is null, bail");
}
+ } else {
// This is a very specific fix to handle the case where the phone receives an
// incoming call during the time we're trying to setup the mms connection.
// When the call ends, restart the process of mms connectivity.
- if (networkInfo != null &&
- Phone.REASON_VOICE_CALL_ENDED.equals(networkInfo.getReason())) {
+ if (Phone.REASON_VOICE_CALL_ENDED.equals(mmsNetworkInfo.getReason())) {
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
Log.v(TAG, " reason is " + Phone.REASON_VOICE_CALL_ENDED +
", retrying mms connectivity");
}
renewMmsConnectivity();
+ return;
}
- return;
- }
- if (!networkInfo.isConnected()) {
- if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
- Log.v(TAG, " TYPE_MOBILE_MMS not connected, bail");
+ if (mmsNetworkInfo.isConnected()) {
+ TransactionSettings settings = new TransactionSettings(
+ TransactionService.this, mmsNetworkInfo.getExtraInfo());
+ // If this APN doesn't have an MMSC, wait for one that does.
+ if (TextUtils.isEmpty(settings.getMmscUrl())) {
+ Log.v(TAG, " empty MMSC url, bail");
+ return;
+ }
+ mServiceHandler.processPendingTransaction(null, settings);
+ } else {
+ if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
+ Log.v(TAG, " TYPE_MOBILE_MMS not connected, bail");
+ }
+
+ // Retry mms connectivity once it's possible to connect
+ if (mmsNetworkInfo.isAvailable()) {
+ if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
+ Log.v(TAG, " retrying mms connectivity for it's available");
+ }
+ renewMmsConnectivity();
+ }
}
- return;
}
-
- TransactionSettings settings = new TransactionSettings(
- TransactionService.this, networkInfo.getExtraInfo());
-
- // If this APN doesn't have an MMSC, wait for one that does.
- if (TextUtils.isEmpty(settings.getMmscUrl())) {
- Log.v(TAG, " empty MMSC url, bail");
- return;
- }
-
- renewMmsConnectivity();
- mServiceHandler.processPendingTransaction(null, settings);
}
};
}
diff --git a/src/com/android/mms/ui/IconListAdapter.java b/src/com/android/mms/ui/IconListAdapter.java
index e52a0d2..288be7e 100644
--- a/src/com/android/mms/ui/IconListAdapter.java
+++ b/src/com/android/mms/ui/IconListAdapter.java
@@ -35,7 +35,33 @@
public class IconListAdapter extends ArrayAdapter<IconListAdapter.IconListItem> {
protected LayoutInflater mInflater;
private static final int mResource = R.layout.icon_list_item;
+ private ViewHolder mViewHolder;
+ static class ViewHolder {
+ private View mView;
+ private TextView mTextView;
+ private ImageView mImageView;
+
+ public ViewHolder(View view) {
+ mView = view;
+ }
+
+ public TextView getTextView() {
+ if (mTextView == null) {
+ mTextView = (TextView) mView.findViewById(R.id.text1);
+ }
+
+ return mTextView;
+ }
+
+ public ImageView getImageView() {
+ if (mImageView == null) {
+ mImageView = (ImageView) mView.findViewById(R.id.icon);
+ }
+
+ return mImageView;
+ }
+ }
public IconListAdapter(Context context,
List<IconListItem> items) {
super(context, mResource, items);
@@ -44,22 +70,22 @@
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- TextView text;
- ImageView image;
-
View view;
if (convertView == null) {
view = mInflater.inflate(mResource, parent, false);
+ mViewHolder = new ViewHolder(view);
+ view.setTag(mViewHolder);
} else {
view = convertView;
+ mViewHolder = (ViewHolder) view.getTag();
}
// Set text field
- text = (TextView) view.findViewById(R.id.text1);
+ TextView text = mViewHolder.getTextView();
text.setText(getItem(position).getTitle());
// Set resource icon
- image = (ImageView) view.findViewById(R.id.icon);
+ ImageView image = mViewHolder.getImageView();
image.setImageResource(getItem(position).getResource());
return view;
diff --git a/src/com/android/mms/ui/ManageSimMessages.java b/src/com/android/mms/ui/ManageSimMessages.java
index beadb54..e783294 100644
--- a/src/com/android/mms/ui/ManageSimMessages.java
+++ b/src/com/android/mms/ui/ManageSimMessages.java
@@ -150,6 +150,8 @@
// Let user know the SIM is empty
updateState(SHOW_EMPTY);
}
+ // Show option menu when query complete.
+ invalidateOptionsMenu();
}
}
diff --git a/src/com/android/mms/ui/MessageListItem.java b/src/com/android/mms/ui/MessageListItem.java
index 880b7b6..ffe06fb 100644
--- a/src/com/android/mms/ui/MessageListItem.java
+++ b/src/com/android/mms/ui/MessageListItem.java
@@ -212,6 +212,7 @@
mDateView.setText(buildTimestampLine(msgSizeText + " " + mMessageItem.mTimestamp));
switch (mMessageItem.getMmsDownloadStatus()) {
+ case DownloadManager.STATE_PRE_DOWNLOADING:
case DownloadManager.STATE_DOWNLOADING:
showDownloadingAttachment();
break;
@@ -246,6 +247,9 @@
intent.putExtra(TransactionBundle.TRANSACTION_TYPE,
Transaction.RETRIEVE_TRANSACTION);
mContext.startService(intent);
+
+ DownloadManager.getInstance().markState(
+ mMessageItem.mMessageUri, DownloadManager.STATE_PRE_DOWNLOADING);
}
});
break;
diff --git a/src/com/android/mms/ui/MessageUtils.java b/src/com/android/mms/ui/MessageUtils.java
index 57075f8..502bfde 100644
--- a/src/com/android/mms/ui/MessageUtils.java
+++ b/src/com/android/mms/ui/MessageUtils.java
@@ -904,6 +904,7 @@
// Launch the slideshow activity to play/view.
Intent intent = new Intent(context, SlideshowActivity.class);
intent.setData(msgUri);
+ intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
if (requestCode > 0 && context instanceof Activity) {
((Activity)context).startActivityForResult(intent, requestCode);
} else {
diff --git a/src/com/android/mms/ui/RecipientsEditor.java b/src/com/android/mms/ui/RecipientsEditor.java
index 7cbb066..4de2118 100644
--- a/src/com/android/mms/ui/RecipientsEditor.java
+++ b/src/com/android/mms/ui/RecipientsEditor.java
@@ -280,6 +280,13 @@
}
private int pointToPosition(int x, int y) {
+ // Check layout before getExtendedPaddingTop().
+ // mLayout is used in getExtendedPaddingTop().
+ Layout layout = getLayout();
+ if (layout == null) {
+ return -1;
+ }
+
x -= getCompoundPaddingLeft();
y -= getExtendedPaddingTop();
@@ -287,11 +294,6 @@
x += getScrollX();
y += getScrollY();
- Layout layout = getLayout();
- if (layout == null) {
- return -1;
- }
-
int line = layout.getLineForVertical(y);
int off = layout.getOffsetForHorizontal(line, x);
diff --git a/src/com/android/mms/ui/SlideshowAttachmentView.java b/src/com/android/mms/ui/SlideshowAttachmentView.java
index 22dccef..03d50e5 100644
--- a/src/com/android/mms/ui/SlideshowAttachmentView.java
+++ b/src/com/android/mms/ui/SlideshowAttachmentView.java
@@ -125,7 +125,7 @@
}
public void reset() {
- mImageView.setImageURI(null);
+ mImageView.setImageBitmap(null);
mTextView.setText("");
}
diff --git a/src/com/android/mms/ui/SlideshowPresenter.java b/src/com/android/mms/ui/SlideshowPresenter.java
index 64af07b..acb7a01 100644
--- a/src/com/android/mms/ui/SlideshowPresenter.java
+++ b/src/com/android/mms/ui/SlideshowPresenter.java
@@ -200,7 +200,7 @@
}
if (dataChanged) {
- view.setImage(image.getSrc(), image.getBitmap(r.getWidth(), r.getHeight()));
+ view.setImage(image.getSrc(), image.getBitmap(transformedWidth, transformedHeight));
}
if (view instanceof AdaptableSlideViewInterface) {
diff --git a/src/com/android/mms/util/DownloadManager.java b/src/com/android/mms/util/DownloadManager.java
index 5210597..3e061e3 100644
--- a/src/com/android/mms/util/DownloadManager.java
+++ b/src/com/android/mms/util/DownloadManager.java
@@ -57,6 +57,7 @@
public static final int STATE_DOWNLOADING = 0x81;
public static final int STATE_TRANSIENT_FAILURE = 0x82;
public static final int STATE_PERMANENT_FAILURE = 0x87;
+ public static final int STATE_PRE_DOWNLOADING = 0x88;
private final Context mContext;
private final Handler mHandler;
diff --git a/src/com/android/mms/util/ThumbnailManager.java b/src/com/android/mms/util/ThumbnailManager.java
index 3834168..681ba46 100644
--- a/src/com/android/mms/util/ThumbnailManager.java
+++ b/src/com/android/mms/util/ThumbnailManager.java
@@ -252,6 +252,8 @@
bitmap = getBitmap(mIsVideo);
} catch (IllegalArgumentException e) {
Log.e(TAG, "Couldn't load bitmap for " + mUri, e);
+ } catch (OutOfMemoryError e) {
+ Log.e(TAG, "Couldn't load bitmap for " + mUri, e);
}
final Bitmap resultBitmap = bitmap;
diff --git a/src/com/android/mms/widget/MmsWidgetProvider.java b/src/com/android/mms/widget/MmsWidgetProvider.java
index a050f68..99b7903 100644
--- a/src/com/android/mms/widget/MmsWidgetProvider.java
+++ b/src/com/android/mms/widget/MmsWidgetProvider.java
@@ -67,10 +67,8 @@
MmsWidgetProvider.class));
// We need to update all Mms appwidgets on the home screen.
- for (int appWidgetId : appWidgetIds) {
- appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId,
- R.id.conversation_list);
- }
+ appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds,
+ R.id.conversation_list);
} else {
super.onReceive(context, intent);
}
diff --git a/src/com/android/mms/widget/MmsWidgetService.java b/src/com/android/mms/widget/MmsWidgetService.java
index 4497e67..a0644a8 100644
--- a/src/com/android/mms/widget/MmsWidgetService.java
+++ b/src/com/android/mms/widget/MmsWidgetService.java
@@ -16,6 +16,7 @@
package com.android.mms.widget;
+import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
@@ -183,9 +184,8 @@
if (Log.isLoggable(LogTag.WIDGET, Log.VERBOSE)) {
Log.v(TAG, "getConversationCount");
}
- synchronized (sWidgetLock) {
- return Math.min(mConversationCursor.getCount(), MAX_CONVERSATIONS_COUNT);
- }
+
+ return Math.min(mConversationCursor.getCount(), MAX_CONVERSATIONS_COUNT);
}
/*
@@ -301,8 +301,11 @@
RemoteViews view = new RemoteViews(mContext.getPackageName(), R.layout.widget_loading);
view.setTextViewText(
R.id.loading_text, mContext.getText(R.string.view_more_conversations));
- view.setOnClickFillInIntent(R.id.widget_loading,
- new Intent(mContext, ConversationList.class));
+ PendingIntent pendingIntent =
+ PendingIntent.getActivity(mContext, 0, new Intent(mContext,
+ ConversationList.class),
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ view.setOnClickPendingIntent(R.id.widget_loading, pendingIntent);
return view;
}