现在的位置: 首页 > 综合 > 正文

Android入门-短信-彩信部分内容的获取方法

2018年03月19日 ⁄ 综合 ⁄ 共 4856字 ⁄ 字号 评论关闭

android短信模块中,短信彩信的收发是重点,不同于短信,基本所有短信元素全部保存在mmssms.db的sms表中。

注:mmssms.db在/data/data/com.previder.telephony/databases/下

关于mmssms.db的表的具体定义可以看这个博客哦~

http://blog.csdn.net/t12x3456/article/details/9336869

彩信的存取是pdu表,pdu表里面通过各种外键来将彩信的各元素联系起来,来看一下彩信pdu表中的元素有哪些:

 

这些数据源代表的意义通过命名可以稍微了解到一些,如sub存储的彩信主题,locked存储的是该信息是否锁定。表格元素的设定各芯片厂商各不相同,对于手机内置应用的定制和功能开发,也会有修改到这些表。这里不是我们的讨论重点。

下面主要将到怎样在代码中通过cursor组合外键来来获取彩信需要显示的部分信息,已彩信在notification显示时获取的方法为例说明。代码中类和常量的定义未加说明,可以从名称理解。

select的定义,即projection:

private static final String[] MMS_STATUS_PROJECTION = new String[] {
        Mms.THREAD_ID, Mms.DATE, Mms._ID, Mms.SUBJECT, Mms.SUBJECT_CHARSET };

where的定义,即判断条件:

private static final String NEW_INCOMING_MM_CONSTRAINT =
            "(" + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_INBOX
            + " AND " + Mms.SEEN + "=0"
            + " AND (" + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_NOTIFICATION_IND
            + " OR " + Mms.MESSAGE_TYPE + "=" + MESSAGE_TYPE_RETRIEVE_CONF + "))";

获取查询游标:

Cursor cursor = SqliteWrapper.query(context, resolver, Mms.CONTENT_URI,
                            MMS_STATUS_PROJECTION, NEW_INCOMING_MM_CONSTRAINT,
                            null, Mms.DATE + " desc");

 

表设计里面甚至彩信发送人地址都没有!太过分了,那首先我们获取address和联系人对象:

long msgId = cursor.getLong(COLUMN_MMS_ID);//获取彩信pdu的id
Uri msgUri = Mms.CONTENT_URI.buildUpon().appendPath(
    Long.toString(msgId)).build();//根据msgId查询这条信息Uri
String address = AddressUtils.getFrom(context, msgUri);//根据Uri和上下文获取发信人地址

Contact contact = Contact.get(address, false);//根据地址获取联系人对象

 

(1)分析下AddressUtils.getFrom(context, msgUri);其实也很简单,就是另外一个查询数据库的操作,直接上源码,有心人可以把这个查询和上面查询组合,不过好复杂的样子,我讨厌数据库。

public static String getFrom(Context context, Uri uri) {
        String msgId = uri.getLastPathSegment();
        Uri.Builder builder = Mms.CONTENT_URI.buildUpon();

        builder.appendPath(msgId).appendPath("addr");

        Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
                            builder.build(), new String[] {Addr.ADDRESS, Addr.CHARSET},
                            Addr.TYPE + "=" + PduHeaders.FROM, null, null);

        if (cursor != null) {
            try {
                if (cursor.moveToFirst()) {
                    String from = cursor.getString(0);

                    if (!TextUtils.isEmpty(from)) {
                        byte[] bytes = PduPersister.getBytes(from);
                        int charset = cursor.getInt(1);
                        return new EncodedStringValue(charset, bytes)
                                .getString();
                    } else { /// M: @{
                        Log.d(TAG, "getFrom EncodedStringValue1 is null");
                    }
                    /// @}
                }
            } finally {
                cursor.close();
            }
        }
        /// M: @{
        Log.d(TAG, "getFrom EncodedStringValue2 is null");
        /// @}
        return context.getString(R.string.hidden_sender_address);
    }

 

(2)再分析Contact.get(address, false);直接上源码吧,我也不分析了- - 原因同上!

private Contact get(String number, boolean isMe, boolean canBlock) {
            if (Log.isLoggable(LogTag.CONTACT, Log.DEBUG)) {
                logWithTrace("get(%s, %s, %s)", number, isMe, canBlock);
            }
            final Object obj = new Object();
            if (TextUtils.isEmpty(number)) {
                number = "";        // In some places (such as Korea), it's possible to receive
                                    // a message without the sender's address. In this case,
                                    // all such anonymous messages will get added to the same
                                    // thread.
            }
            // Always return a Contact object, if if we don't have an actual contact
            // in the contacts db.
            Contact contact = internalGet(number, isMe);
            Runnable r = null;

            synchronized (contact) {
                // If there's a query pending and we're willing to block then
                // wait here until the query completes.

                /// M: make sure the block can update contact immediately @{
                if (canBlock) {
                    contact.mIsStale = true;
                }
                /// @}

                // If we're stale and we haven't already kicked off a query then kick
                // it off here.
                if (contact.mIsStale) {
                    contact.mIsStale = false;

                    if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
                        log("async update for " + contact.toString() + " canBlock: " + canBlock +
                                " isStale: " + contact.mIsStale);
                    }

                    final Contact c = contact;
                    r = new Runnable() {
                        public void run() {
                            updateContact(c);
                            /// M:@{
                            synchronized (obj) {
                                obj.notifyAll();
                            }
                            c.mQueryPending = false;
                            /// @}
                        }
                    };
                }
            }
            // do this outside of the synchronized so we don't hold up any
            // subsequent calls to "get" on other threads
            //MmsLog.d(M_TAG, "get(" + number + ", " + isMe + ", " + canBlock + "): mWaitTime = " + mWaitTime);
            if (r != null) {
                if (canBlock) {
                    /// M: @{
                    pushTask(r);
                    synchronized (obj) {
                        try {
                            obj.wait(mWaitTime);
                        } catch (InterruptedException ex) {
                            // do nothing
                        }
                    }
                    if (mWaitTime < mMaxWaitTime) {
                        mWaitTime += 5;
                    }
                } else {
                    pushTask(r);
                }
            } else {
                if ((mWaitTime -= mMinWaitTime) < mMinWaitTime) {
                    mWaitTime = mMinWaitTime;
                }
            }
            /// @}
            return contact;
 }

地址和联系人获取到之后,我们开始获取彩信主题,表内有这个元素,直接获取,可能有些编码要处理,这个就不写了。

然后根据thread_id开始各种查询了!

long threadId = cursor.getLong(COLUMN_THREAD_ID);
long timeMillis = cursor.getLong(COLUMN_DATE) * 1000;
Bitmap attachedPicture = null;
String messageBody = null;
int attachmentType = WorkingMessage.TEXT;

try {
    GenericPdu pdu = sPduPersister.load(msgUri);//获取Uri对应pdu类
    if (pdu != null && pdu instanceof MultimediaMessagePdu) {
        SlideshowModel slideshow = SlideshowModel.createFromPduBody(context,((MultimediaMessagePdu)pdu).getBody());//彩信的幻灯片
        attachmentType = getAttachmentType(slideshow);
        SlideModel firstSlide = slideshow.get(0);//获取第一张幻灯片,因为在通知栏只需要显示彩信预览即可
        if (firstSlide != null) {
            if (cursor.getCount() <= 1) {
                if (firstSlide.hasImage()) {
                    int maxDim = dp2Pixels(MAX_BITMAP_DIMEN_DP);
                    attachedPicture = firstSlide.getImage().getBitmap(maxDim, maxDim);//获取第一张幻灯片的图片
                }
            }
            if (firstSlide.hasText()) {
                messageBody = firstSlide.getText().getText();
            }
        }
    }
} catch (final MmsException e) {
    Log.e(TAG, "MmsException loading uri: " + msgUri, e);
}

这样彩信预览相关的元素就全部获取到了。基本都是些查表和对接口的掌握。

 

上述的主体方法在\packages\apps\Mms\src\com\android\mms\transaction\MessagingNotification.java中有定义。

小伙伴们也可自行前往观看。

 

抱歉!评论已关闭.