【操作步骤】:编辑一条彩信,附件选择添加音频(外部音频),返回到编辑界面选择play,菜单键选择view slideshow

【测试结果】:不能播放,没有声音

【预期结果】:可以播放

根据以往的经验(之前也有一片博文涉及到类似的功能)这里首先想到的是乱码,通过查看数据库,也证实了这个想法;

因此,从文件管理器中共享一个中文文件名的音频文件(当然通过测试其他任何格式的文件包括图片,视频等只要是中文乱码则都有相同的问题)到短信中(文件管理器通过ACTION_SEND启动ComposeMessageActivity,该Activity在清单文件中注册了该Action);

CompseMessageActivity通过handleSendIntent()方法来接受Intent中的数据:

private boolean handleSendIntent() {

        Intent intent = getIntent();

        Bundle extras = intent.getExtras();

        if (extras == null) {

            return false;

        }



        final String mimeType = intent.getType();

        String action = intent.getAction();

        if (Intent.ACTION_SEND.equals(action)) {

            if (extras.containsKey(Intent.EXTRA_STREAM)) {

                final Uri uri = (Uri)extras.getParcelable(Intent.EXTRA_STREAM);

                getAsyncDialog().runAsync(new Runnable() {

                    @Override

                    public void run() {

                        mAttachFileUri = uri;

                        addAttachment(mimeType, uri, false);

                    }

                }, null, R.string.adding_attachments_title);

                return true;

            } else if (extras.containsKey(Intent.EXTRA_TEXT)) {

                mWorkingMessage.setText(extras.getString(Intent.EXTRA_TEXT));

                return true;

            }

        } else if ((Intent.ACTION_SEND_MULTIPLE.equals(action) &&

                extras.containsKey(Intent.EXTRA_STREAM)) || mIsSendMultiple) {

            SlideshowModel slideShow = mWorkingMessage.getSlideshow();

            final ArrayList<Parcelable> uris = extras.getParcelableArrayList(Intent.EXTRA_STREAM);

            if (uris.size() > 0) {

                mIsSendMultiple = true;

            }

            int currentSlideCount = slideShow != null ? slideShow.size() : 0;

            int importCount = uris.size();

            if (importCount + currentSlideCount > SlideshowEditor.MAX_SLIDE_NUM) {

                importCount = Math.min(SlideshowEditor.MAX_SLIDE_NUM - currentSlideCount,

                        importCount);

                Toast.makeText(ComposeMessageActivity.this,

                        getString(R.string.too_many_attachments,

                                SlideshowEditor.MAX_SLIDE_NUM, importCount),

                                Toast.LENGTH_LONG).show();

            }



            // Attach all the pictures/videos asynchronously off of the UI thread.

            // Show a progress dialog if adding all the slides hasn't finished

            // within half a second.

            final int numberToImport = importCount;

            getAsyncDialog().runAsync(new Runnable() {

                @Override

                public void run() {

                    for (int i = 0; i < numberToImport; i++) {

                        Parcelable uri = uris.get(i);

                        addAttachment(mimeType, (Uri) uri, true);

                    }

                    updateMmsSizeIndicator();

                }

            }, null, R.string.adding_attachments_title);

            return true;

        }

        return false;

    }

调用addAttachment()方法;

private void addAttachment(String type, Uri uri, boolean append) {

        if (uri != null) {

            // When we're handling Intent.ACTION_SEND_MULTIPLE, the passed in items can be

            // videos, and/or images, and/or some other unknown types we don't handle. When

            // a single attachment is "shared" the type will specify an image or video. When

            // there are multiple types, the type passed in is "*/*". In that case, we've got

            // to look at the uri to figure out if it is an image or video.

            boolean wildcard = "*/*".equals(type);

            if (type.startsWith("image/")

                    || (wildcard && uri.toString().startsWith(mImageUri))

                    || (wildcard && isImageFile(uri))) {

                addImage(uri, append);

            } else if (type.startsWith("video/")

                    || (wildcard && uri.toString().startsWith(mVideoUri))

                    || (wildcard && isVideoFile(uri))) {

                addVideo(uri, append);

            } else if (type.startsWith("audio/")

                    || (wildcard && uri.toString().startsWith(mAudioUri))

                    || (wildcard && isAudioFile(uri))) {

                addAudio(uri, append);

            } else if (SystemProperties.getBoolean("persist.env.mms.vcard", true)

                    && (type.equals("text/x-vcard")

                    || (wildcard && isVcardFile(uri)))) {

                addVcard(uri);

            } else {

                // Add prompt when file type is not image/video/audio.

                Message msg = Message.obtain(mAddAttachmentHandler,

                        MSG_ADD_ATTACHMENT_FAILED, uri);

                mAddAttachmentHandler.sendMessage(msg);

            }

        }

    }

接下来会调用addVideo-->setAttachement()等方法进行设置附件,而这写操作均没有进行持久化操作。那么持久化操作在哪里呢?

当我们添加过附件之后,去查看或者播放幻灯片的时候会首先对附件内容进行持久化操作。这里我们调用了MessageUtils.java中的viewMmsMessageAttachment()方法。

 public static void viewMmsMessageAttachment(final Activity activity, final Uri msgUri,

            final SlideshowModel slideshow, final int requestCode, AsyncDialog asyncDialog)
{

        boolean isSimple = (slideshow == null) ? false : slideshow.isSimple();

        if (isSimple) {

            // In attachment-editor mode, we only ever have one slide.

            MessageUtils.viewSimpleSlideshow(activity, slideshow);

        } else {

            // The user wants to view the slideshow. We have to persist the slideshow parts

            // in a background task. If the task takes longer than a half second, a progress dialog

            // is displayed. Once the PDU persisting is done, another runnable on the UI thread get

            // executed to start the SlideshowActivity.

            asyncDialog.runAsync(new Runnable() {

                @Override

                public void run() {

                    // If a slideshow was provided, save it to disk first.

                    if (slideshow != null) {

                        PduPersister persister = PduPersister.getPduPersister(activity);

                        try {

                            PduBody pb = slideshow.toPduBody();

                            persister.updateParts(msgUri, pb, null);

                            slideshow.sync(pb);

                        } catch (MmsException e) {

                            Log.e(TAG, "Unable to save message for preview");

                            return;

                        }

                    }

                }

            }, new Runnable() {

                @Override

                public void run() {

                    // Once the above background thread is complete, this runnable is run

                    // on the UI thread to launch the slideshow activity.

                    launchSlideshowActivity(activity, msgUri, requestCode);

                }

            }, R.string.building_slideshow_title);

        }

    }

上述代码中调用了PudPersister类中的updateParts()方法;

public void updateParts(Uri uri, PduBody body, HashMap<Uri, InputStream> preOpenedFiles)

            throws MmsException {

        try {

            PduCacheEntry cacheEntry;

            synchronized(PDU_CACHE_INSTANCE) {

                if (PDU_CACHE_INSTANCE.isUpdating(uri)) {

                    if (LOCAL_LOGV) {

                        Log.v(TAG, "updateParts: " + uri + " blocked by isUpdating()");

                    }

                    try {

                        PDU_CACHE_INSTANCE.wait();

                    } catch (InterruptedException e) {

                        Log.e(TAG, "updateParts: ", e);

                    }

                    cacheEntry = PDU_CACHE_INSTANCE.get(uri);

                    if (cacheEntry != null) {

                        ((MultimediaMessagePdu) cacheEntry.getPdu()).setBody(body);

                    }

                }

                // Tell the cache to indicate to other callers that this item

                // is currently being updated.

                PDU_CACHE_INSTANCE.setUpdating(uri, true);

            }



            ArrayList<PduPart> toBeCreated = new ArrayList<PduPart>();

            HashMap<Uri, PduPart> toBeUpdated = new HashMap<Uri, PduPart>();



            int partsNum = body.getPartsNum();

            StringBuilder filter = new StringBuilder().append('(');

            for (int i = 0; i < partsNum; i++) {

                PduPart part = body.getPart(i);

                Uri partUri = part.getDataUri();

                if ((partUri == null) || TextUtils.isEmpty(partUri.getAuthority())

                        || !partUri.getAuthority().startsWith("mms")) {

                    toBeCreated.add(part);

                } else {

                    toBeUpdated.put(partUri, part);



                    // Don't use 'i > 0' to determine whether we should append

                    // 'AND' since 'i = 0' may be skipped in another branch.

                    if (filter.length() > 1) {

                        filter.append(" AND ");

                    }



                    filter.append(Part._ID);

                    filter.append("!=");

                    DatabaseUtils.appendEscapedSQLString(filter, partUri.getLastPathSegment());

                }

            }

            filter.append(')');



            long msgId = ContentUris.parseId(uri);



            // Remove the parts which doesn't exist anymore.

            SqliteWrapper.delete(mContext, mContentResolver,

                    Uri.parse(Mms.CONTENT_URI + "/" + msgId + "/part"),

                    filter.length() > 2 ? filter.toString() : null, null);



            // Create new parts which didn't exist before.

            for (PduPart part : toBeCreated) {

                persistPart(part, msgId, preOpenedFiles);

            }




            // Update the modified parts.

            for (Map.Entry<Uri, PduPart> e : toBeUpdated.entrySet()) {

                updatePart(e.getKey(), e.getValue(), preOpenedFiles);

            }


        } finally {

            synchronized(PDU_CACHE_INSTANCE) {

                PDU_CACHE_INSTANCE.setUpdating(uri, false);

                PDU_CACHE_INSTANCE.notifyAll();

            }

        }

    }

根据上述代码我们可以发现,如果是第一次,也就是没有持久化的时候则会进行insert操作,如果已经执行过insert则会进行update操作,在之前的一篇博客中已经描述过具体的修改方法,这里不再详细赘述,只是把修改的内容给展示出来,其他操作请参考我之前写的一篇博客,地址为:http://blog.csdn.net/huangyabin001/article/details/27523961

修改后:

private void updatePart(Uri uri, PduPart part, HashMap<Uri, InputStream> preOpenedFiles)

            throws MmsException {

        ContentValues values = new ContentValues(7);



        int charset = part.getCharset();

        if (charset != 0 ) {

            values.put(Part.CHARSET, charset);

        }



        String contentType = null;

        if (part.getContentType() != null) {

            contentType = toIsoString(part.getContentType());

            values.put(Part.CONTENT_TYPE, contentType);

        } else {

            throw new MmsException("MIME type of the part must be set.");

        }



        if (part.getFilename() != null) {

            String fileName = new String(part.getFilename());

            values.put(Part.FILENAME, fileName);

        }



        if (part.getName() != null) {

            String name = new String(part.getName());

            values.put(Part.NAME, name);

        }



        String value = null;

        if (part.getContentDisposition() != null) {

            value = toIsoString(part.getContentDisposition());

            values.put(Part.CONTENT_DISPOSITION,value);

        }



        if (part.getContentId() != null) {

            byte[] byteContentId=part.getContentId();

            int encodeContentId=detectEncoding(byteContentId);

            try{

                switch(encodeContentId){

                    case GB2312:

                        value=new String(byteContentId,"GB2312");

                    break;

                    case ASCII:

                        value=new String(byteContentId,"ASCII");

                    break;

                    case UTF8:

                        value=new String(byteContentId,"UTF-8");

                    break;

                    case UNICODE:

                        value=new String(byteContentId,"Unicode");

                    break;

                    default:

                        value = toIsoString(byteContentId);

                    break;

                }

                values.put(Part.CONTENT_ID, value);

            }catch(Exception e){

                e.printStackTrace();

            }

        }



        if (part.getContentLocation() != null) {

            byte[] byteContentLocation=part.getContentLocation();

            int encodeContentLocation=detectEncoding(byteContentLocation);

            try{

                switch(encodeContentLocation){

                    case GB2312:

                        value=new String(byteContentLocation,"GB2312");

                    break;

                    case ASCII:

                        value=new String(byteContentLocation,"ASCII");

                    break;

                    case UTF8:

                        value=new String(byteContentLocation,"UTF-8");

                    break;

                    case UNICODE:

                        value=new String(byteContentLocation,"Unicode");

                    break;

                    default:

                        value = toIsoString(byteContentLocation);

                    break;

                }

                values.put(Part.CONTENT_LOCATION,value);

            }catch(Exception e){

                e.printStackTrace();

            }

        }

        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);



        // Only update the data when:

        // 1. New binary data supplied or

        // 2. The Uri of the part is different from the current one.

        if ((part.getData() != null)

                || (uri != part.getDataUri())) {

            persistData(part, uri, contentType, preOpenedFiles);

        }

    }

修改前:

private void updatePart(Uri uri, PduPart part, HashMap<Uri, InputStream> preOpenedFiles)

            throws MmsException {

        ContentValues values = new ContentValues(7);



        int charset = part.getCharset();

        if (charset != 0 ) {

            values.put(Part.CHARSET, charset);

        }



        String contentType = null;

        if (part.getContentType() != null) {

            contentType = toIsoString(part.getContentType());

            values.put(Part.CONTENT_TYPE, contentType);

        } else {

            throw new MmsException("MIME type of the part must be set.");

        }



        if (part.getFilename() != null) {

            String fileName = new String(part.getFilename());

            values.put(Part.FILENAME, fileName);

        }



        if (part.getName() != null) {

            String name = new String(part.getName());

            values.put(Part.NAME, name);

        }



        Object value = null;

        if (part.getContentDisposition() != null) {

            value = toIsoString(part.getContentDisposition());

            values.put(Part.CONTENT_DISPOSITION, (String) value);

        }



        if (part.getContentId() != null) {

            value = toIsoString(part.getContentId());

            values.put(Part.CONTENT_ID, (String) value);

        }



        if (part.getContentLocation() != null) {

            value = toIsoString(part.getContentLocation());

            values.put(Part.CONTENT_LOCATION, (String) value);

        }



        SqliteWrapper.update(mContext, mContentResolver, uri, values, null, null);



        // Only update the data when:

        // 1. New binary data supplied or

        // 2. The Uri of the part is different from the current one.

        if ((part.getData() != null)

                || (uri != part.getDataUri())) {

            persistData(part, uri, contentType, preOpenedFiles);

        }

    }

解决:编辑一条彩信,附件选择添加音频,返回到编辑界面选择play,不能播放,没有声音的更多相关文章

  1. 【登录异常解决】Ubuntu 输入正确的密码后重新返回到登陆界面

    症状 Ubuntu 输入正确的密码后,黑屏一闪,重新返回到登陆界面. 原因一:主目录下的.Xauthority文件拥有者变成了root,从而以用户登陆的时候无法都取.Xauthority文件.说明:X ...

  2. android短彩信附件机制

    将一些认识写下来,和大家交流一下,同时也方便自己复习. 用户可以通过附件按钮,添加附件.以添加幻灯片为例: 如果点击幻灯片,会走如下代码: ComposeMessageActivity.java pr ...

  3. 编辑技巧分享如何给PDF添加注释

    纸质的文件想要添加注释就直接拿笔在上面添加就好了,那么电子文件要怎么添加注释呢,今天小编就以我们现在经常使用到的PDF文档来为大家分享怎么添加注释.   1. 我们需要在百度中搜索并下载并安装一款PD ...

  4. python全栈开发day61-django简单的出版社网站展示,添加,删除,编辑(单表的增删改查)

    day61 django内容回顾: 1. 下载: pip install django==1.11.14 pip install -i 源 django==1.11.14 pycharm 2. 创建项 ...

  5. 【转载】win10解决设置默认打开方式不生效问题(双击每次都要选择默认打开程序)

    win10解决设置默认打开方式不生效问题(双击每次都要选择默认打开程序) 以下文章 部分选自 https://blog.csdn.net/shan165310175/article/details/8 ...

  6. Winform 多个窗口编辑同一条数据同步的实现

    场景: 一个主窗口中,可以在列表(DataGridView)里选中一条记录编辑,打开一个编辑窗口(非模态窗口),编辑窗口保存后需要刷新父窗口,由于编辑窗口是非模态窗口,如果打开了多个窗口,并且都是编辑 ...

  7. 关于Delphi cxGrid主从表中从表只能编辑第一条记录的问题

    在Delphi cxGrid主从表中从表只能编辑第一条记录,这个问题是由于设置主从关联字段错误造成的. 从表DBtableView2的keyfieldnames,DetailKeyFieldNames ...

  8. 树莓派Zero W添加音频输出

    编译:陈拓 chentuo@ms.xab.ac.cn 2018.06.07/2018.07.14 原文:Adding Basic Audio Ouput to Raspberry Pi Zero ht ...

  9. 安装Linux 16.04 时,选择好分区后,进到选择地点的界面后,总是闪退,退到最原始的界面

    这两天装 Linux 系统,总是遇到一个很蛋疼的问题: 当你累死累活把分区什么的都设置好了之后,在输入了系统名字,开机密码那几项之后,再选择地点的时候(如:选择 "上海"),然后就 ...

随机推荐

  1. stm32 iic读取mpu6050失败 改用串口

    mpu6050使用iic一直失败.放弃治疗,使用串口... #include "led.h" #include "mpu6050.h" #include &qu ...

  2. 01_Spark基础

    1.1.Spark Ecosystem BlinkDB: 允许用户定义一个错误范围,BlinkDB将在用户给定的错误范围内,尽可能快的提供查询结果 1.2.Spark愿景 1.3.Spark简介 1) ...

  3. python闭包closure

    在讨论闭包之前,先总结一下python的命名空间namespace,一般的语言都是通过namespace来识别名字标识,无论是变量,对象,函数等等.python划分3个名字空间层次,local:局部, ...

  4. 【Ctsc2011】幸福路径

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2306 给定一张有向图,每个点有权值,蚂蚁从某个节点出发,初始体力值为$1$,每走一条边$体 ...

  5. Java中引用的详解

    Java中没有指针,到处都是引用(除了基本类型).所以,当然,你肯定知道java的引用,并用了很久,但是是不是对此了解地比较全面?而这些引用有什么作用,且有什么不同呢?Java中有个java.lang ...

  6. hdu 2586 How far away ? 带权lca

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) P ...

  7. BeautifulSoup中的find,find_all

    1.一般来说,为了找到BeautifulSoup对象内任何第一个标签入口,使用find()方法. 以上代码是一个生态金字塔的简单展示,为了找到第一生产者,第一消费者或第二消费者,可以使用Beautif ...

  8. Java实现冒泡排序算法

    一.基本思路: 冒泡排序是一种简单的交换类排序.其基本思路是,从头开始扫描待排序的元素,在扫描过程中依次对相邻元素进行比较,将关键字值大的元素后移.每经过 一趟排序后,关键字值最大的元素将移到末尾,此 ...

  9. 『Kaggle』分类任务_决策树&集成模型&DataFrame向量化操作

    决策树这节中涉及到了很多pandas中的新的函数用法等,所以我单拿出来详细的理解一下这些pandas处理过程,进一步理解pandas背后的数据处理的手段原理. 决策树程序 数据载入 pd.read_c ...

  10. vue 右键菜单插件 简单、可扩展、样式自定义的右键菜单

    今天分享的不是技术,今天给大家分享个插件,针对现有的vue右键菜单插件,大多数都是需要使用插件本身自定义的标签,很多地方不方便,可扩展性也很低,所以我决定写了一款自定义指令调用右键菜单(vuerigh ...