Merge "FP2-1515: Fixed Dual Sim SMS Delivery Reports bug" into fp2-dev-v2
diff --git a/src/com/android/mms/model/SlideshowModel.java b/src/com/android/mms/model/SlideshowModel.java
index fbb3bc3..16b6af7 100755
--- a/src/com/android/mms/model/SlideshowModel.java
+++ b/src/com/android/mms/model/SlideshowModel.java
@@ -53,6 +53,7 @@
import com.android.mms.dom.smil.parser.SmilXmlSerializer;
import com.android.mms.layout.LayoutManager;
import com.android.mms.ui.UriImage;
+import com.android.mms.ui.MessageUtils;
import com.google.android.mms.ContentType;
import com.google.android.mms.MmsException;
import com.google.android.mms.pdu.GenericPdu;
@@ -111,7 +112,7 @@
return createFromPduBody(context, getPduBody(context, uri));
}
- public static SlideshowModel createFromPduBody(Context context, PduBody pb) throws MmsException {
+public static SlideshowModel createFromPduBody(Context context, PduBody pb) throws MmsException {
SMILDocument document = SmilHelper.getDocument(pb);
// Create root-layout model.
@@ -148,6 +149,7 @@
int slidesNum = slideNodes.getLength();
ArrayList<SlideModel> slides = new ArrayList<SlideModel>(slidesNum);
int totalMessageSize = 0;
+ boolean isClassCastFailed = false;
for (int i = 0; i < slidesNum; i++) {
// FIXME: This is NOT compatible with the SMILDocument which is
@@ -160,7 +162,16 @@
ArrayList<MediaModel> mediaSet = new ArrayList<MediaModel>(mediaNum);
for (int j = 0; j < mediaNum; j++) {
- SMILMediaElement sme = (SMILMediaElement) mediaNodes.item(j);
+ SMILMediaElement sme = null;
+ try {
+ sme = (SMILMediaElement) mediaNodes.item(j);
+ } catch (ClassCastException e) {
+ // The node may not be a SMILMediaElement but a SMILElement or else
+ // in other mobile phones. So catch the exception and handle it later.
+ isClassCastFailed = true;
+ Log.e(TAG, e.getMessage());
+ continue;
+ }
try {
MediaModel media = MediaModelFactory.getMediaModel(
context, sme, layouts, pb);
@@ -222,6 +233,45 @@
}
}
+ // Add vcard when receive from other products without ref target in smil.
+ int partsNum = pb.getPartsNum();
+ if (needAddUnrecognizedPart(slidesNum,
+ mediaNum, partsNum, isClassCastFailed)) {
+ for (int k = 0; k < partsNum; k++) {
+ PduPart part = pb.getPart(k);
+ String contentType = (new String(part.getContentType())).toLowerCase();
+ if (MessageUtils.OCT_STREAM.equals(contentType)) {
+ byte[] name = part.getName();
+ if (name == null) {
+ name = part.getContentLocation();
+ }
+ if (name != null) {
+ // Convert content type application/oct-stream (which is a vcard) to
+ // application/X-vcard so that this mms can be recognized.
+ contentType = MessageUtils.convertToVcardType(new String(name));
+ }
+ }
+ if (ContentType.TEXT_VCARD.toLowerCase().equals(contentType) ||
+ ContentType.TEXT_VCALENDAR.toLowerCase().equals(contentType)) {
+ byte[] data = part.getContentLocation();
+ if (data == null) {
+ data = part.getName();
+ }
+ MediaModel vMedia = null;
+ if (ContentType.TEXT_VCARD.toLowerCase().equals(contentType)) {
+ vMedia = new VcardModel(context, contentType,
+ new String(data), part.getDataUri());
+ } else {
+ vMedia = new VCalModel(context, contentType,
+ new String(data), part.getDataUri());
+ }
+ mediaSet.add(vMedia);
+ totalMessageSize += vMedia.getMediaSize();
+ break;
+ }
+ }
+ }
+
SlideModel slide = new SlideModel((int) (par.getDur() * 1000), mediaSet);
slide.setFill(par.getFill());
SmilHelper.addParElementEventListeners((EventTarget) par, slide);
@@ -234,6 +284,21 @@
return slideshow;
}
+
+ private static boolean needAddUnrecognizedPart(
+ int slidesNum, int mediaNum, int partsNum, boolean castFailed) {
+ if (slidesNum != 1) {
+ return false;
+ }
+
+ if (mediaNum != partsNum || castFailed) {
+ // Some part is not recognized as a media, need add.
+ return true;
+ } else {
+ return false;
+ }
+ }
+
public PduBody toPduBody() {
if (mPduBodyCache == null) {
mDocumentCache = SmilHelper.getDocument(this);
diff --git a/src/com/android/mms/model/VCalModel.java b/src/com/android/mms/model/VCalModel.java
new file mode 100644
index 0000000..1db266d
--- /dev/null
+++ b/src/com/android/mms/model/VCalModel.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014, CyanogenMod
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.mms.model;
+
+import android.content.Context;
+import android.net.Uri;
+import android.util.Log;
+import com.google.android.mms.ContentType;
+import com.google.android.mms.MmsException;
+import org.w3c.dom.events.Event;
+
+public class VCalModel extends MediaModel {
+ private static final String TAG = MediaModel.TAG;
+
+ public VCalModel(Context context, Uri uri) throws MmsException {
+ this(context, ContentType.TEXT_VCALENDAR, null, uri);
+ initModelFromUri(uri);
+ }
+
+ public VCalModel(Context context, String contentType, String src, Uri uri)
+ throws MmsException {
+ super(context, SmilHelper.ELEMENT_TAG_REF, contentType, src, uri);
+ }
+
+ private void initModelFromUri(Uri uri) throws MmsException {
+ String scheme = uri.getScheme();
+ if (scheme == null) {
+ Log.e(TAG, "The uri's scheme is null.");
+ return;
+ }
+
+ if (scheme.equals("file")) {
+ mSrc = getFileSrc(uri);
+ }
+ initMediaDuration();
+ }
+
+ private String getFileSrc(Uri uri) {
+ String path = Uri.decode(uri.toString());
+ return path.substring(path.lastIndexOf('/') + 1);
+ }
+
+ @Override
+ public void handleEvent(Event evt) {
+ }
+
+ @Override
+ protected boolean isPlayable() {
+ return false;
+ }
+
+ @Override
+ protected void initMediaDuration() throws MmsException {
+ mDuration = 0;
+ }
+
+}
+
diff --git a/src/com/android/mms/model/VcardModel.java b/src/com/android/mms/model/VcardModel.java
new file mode 100644
index 0000000..f62c19c
--- /dev/null
+++ b/src/com/android/mms/model/VcardModel.java
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.mms.model;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.Telephony.Mms.Part;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.google.android.mms.ContentType;
+import com.google.android.mms.MmsException;
+
+import org.w3c.dom.events.Event;
+
+public class VcardModel extends MediaModel {
+ private static final String TAG = MediaModel.TAG;
+
+ private String mLookupUri = null;
+
+ public VcardModel(Context context, Uri uri) throws MmsException {
+ this(context, ContentType.TEXT_VCARD, null, uri);
+ initModelFromUri(uri);
+ }
+
+ public VcardModel(Context context, String contentType, String src, Uri uri)
+ throws MmsException {
+ super(context, SmilHelper.ELEMENT_TAG_REF, contentType, src, uri);
+ if (!TextUtils.isEmpty(src)) {
+ initLookupUri(uri);
+ }
+ }
+
+ private void initModelFromUri(Uri uri) throws MmsException {
+ String scheme = uri.getScheme();
+ if (scheme == null) {
+ Log.e(TAG, "The uri's scheme is null.");
+ return;
+ }
+
+ if (scheme.equals("file")) {
+ mSrc = uri.getLastPathSegment();
+ } else if (scheme.equals("content")){
+ Cursor c = null;
+ try {
+ c = getContentCursor(uri);
+ mLookupUri = getLookupUri(uri,c);
+ mSrc = getLookupSrc(uri,c);
+ } finally {
+ if (c != null) {
+ c.close();
+ c = null;
+ } else {
+ throw new MmsException("Bad URI: " + uri);
+ }
+ }
+ }
+ initMediaDuration();
+ }
+
+ private Cursor getContentCursor(Uri uri) {
+ if(isMmsUri(uri)) {
+ return mContext.getContentResolver().query(uri, null, null, null, null);
+ }
+ return mContext.getContentResolver()
+ .query(getExtraLookupUri(uri), null, null, null, null);
+ }
+
+ private String getLookupUri(Uri uri, Cursor c) {
+ if(isMmsUri(uri))
+ return getMmsLookupUri(uri,c);
+ return getExtraLookupUri(uri).toString();
+ }
+
+ private String getMmsLookupUri(Uri uri, Cursor c) {
+ if (c != null && c.moveToFirst())
+ return c.getString(c.getColumnIndexOrThrow(Part.CONTENT_DISPOSITION));
+ return "";
+ }
+
+ private Uri getExtraLookupUri(Uri uri) {
+ String lookup = uri.getLastPathSegment();
+ Uri lookupUri =
+ Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookup);
+ return lookupUri;
+ }
+
+ private String getLookupSrc(Uri uri, Cursor c) throws MmsException {
+ if(isMmsUri(uri))
+ return getMmsLookupSrc(c);
+ return getExtraSrc(uri,c);
+ }
+
+ private String getMmsLookupSrc(Cursor c) {
+ if (c != null && c.moveToFirst()) {
+ String path = c.getString(c.getColumnIndexOrThrow(Part._DATA));
+ return path.substring(path.lastIndexOf('/') + 1);
+ }
+ return "";
+ }
+
+ private String getExtraSrc(Uri uri, Cursor c) throws MmsException {
+ if (c != null && c.getCount() == 1 && c.moveToFirst()) {
+ String displayName = c.getString(c.getColumnIndexOrThrow(ContactsContract
+ .Contacts.DISPLAY_NAME));
+ return displayName + ".vcf";
+ } else {
+ throw new MmsException("Type of media is unknown.");
+ }
+ }
+
+ private void initLookupUri(Uri uri) {
+ if (isMmsUri(uri)) {
+ ContentResolver cr = mContext.getContentResolver();
+ Cursor c = cr.query(uri, null, null, null, null);
+ try {
+ if (c != null && c.moveToFirst()) {
+ mLookupUri = c.getString(c.getColumnIndexOrThrow(Part.CONTENT_DISPOSITION));
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ c = null;
+ }
+ }
+ }
+ }
+
+ public String getLookupUri() {
+ return mLookupUri;
+ }
+
+ @Override
+ public void handleEvent(Event evt) {
+ }
+
+ @Override
+ protected boolean isPlayable() {
+ return false;
+ }
+
+ @Override
+ protected void initMediaDuration() throws MmsException {
+ mDuration = 0;
+ }
+
+}
+
diff --git a/src/com/android/mms/ui/MessageListItem.java b/src/com/android/mms/ui/MessageListItem.java
index e20ed99..7846876 100755
--- a/src/com/android/mms/ui/MessageListItem.java
+++ b/src/com/android/mms/ui/MessageListItem.java
@@ -334,7 +334,7 @@
if (!sameItem || haveLoadedPdu) {
boolean isSelf = Sms.isOutgoingFolder(mMessageItem.mBoxId);
String addr = isSelf ? null : mMessageItem.mAddress;
- updateAvatarView(mMessageItem.mAddress, false);
+ updateAvatarView(addr, isSelf);
}
// Add SIM sms address above body.
diff --git a/src/com/android/mms/ui/MessageUtils.java b/src/com/android/mms/ui/MessageUtils.java
index ba770f6..15671db 100755
--- a/src/com/android/mms/ui/MessageUtils.java
+++ b/src/com/android/mms/ui/MessageUtils.java
@@ -163,6 +163,17 @@
public static final int PREFER_SMS_STORE_TO_SIM = 1;
private static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
+// Consider oct-strean as the content type of vCard
+ public static final String OCT_STREAM = "application/oct-stream";
+ public static final String VCARD = "vcf";
+
+ // distinguish view vcard from mms but not from contacts.
+ public static final String VIEW_VCARD = "VIEW_VCARD_FROM_MMS";
+ // add for obtain mms data path
+ private static final String MMS_DATA_DIR = "/data/phonedata";
+ private static final String MMS_DATABASE_DIR =
+ "/com.android.providers.telephony/databases/mmssms.db";
+
// add threshold for low memory
private static final int THRESHOLD_LOW_MEM_PERCENTAGE = 5;
// add for obtain mms data path
@@ -524,6 +535,19 @@
}
}
+ public static String convertToVcardType(String src) {
+ if (!TextUtils.isEmpty(src)) {
+ int index = src.lastIndexOf('.');
+ if (index > 0) {
+ String extension = src.substring(index + 1, src.length());
+ if (extension.toLowerCase().equals(VCARD)) {
+ return ContentType.TEXT_VCARD.toLowerCase();
+ }
+ }
+ }
+ return "";
+ }
+
public static int getAttachmentType(SlideshowModel model, MultimediaMessagePdu mmp) {
if (model == null || mmp == null) {
return MessageItem.ATTACHMENT_TYPE_NOT_LOADED;