zoukankan      html  css  js  c++  java
  • 解决Android4.3版本下,手机短彩接收中文文件名附件,中文名字的附件无法保存(第二步:解决从从数据库中读取附件文件名,并在长按后保存附件时,中文乱码导致的无法保存附件)

    从第一步我们发现,在第一步修改之后,在短彩绘画界面中中文附件名的附件已无法显示,经过打印堆栈我们发现还是中文乱码在作祟。下面我们接着进行分析,这次我们从UI层往逻辑处理层进行分析。首先我们找到保存附件操作的页面和相关的代码:

    短彩会话界面ComposeMessageActivity.java类中的MsgListMenuClickListener子类,onMenuItemClick()方法:<TAG 1-1>

     /**
         * Context menu handlers for the message list view.
         */
        private final class MsgListMenuClickListener implements MenuItem.OnMenuItemClickListener {
            private MessageItem mMsgItem;

            public MsgListMenuClickListener(MessageItem msgItem) {
                mMsgItem = msgItem;
            }

            @Override
            public boolean onMenuItemClick(MenuItem item) {
                if (mMsgItem == null) {
                    return false;
                }

                switch (item.getItemId()) {
                    case MENU_EDIT_MESSAGE:
                        editMessageItem(mMsgItem);
                        drawBottomPanel();
                        return true;

                    case MENU_COPY_MESSAGE_TEXT:
                        copyToClipboard(mMsgItem.mBody);
                        return true;

                    case MENU_FORWARD_MESSAGE:
                        if (mMsgItem.isMms() && !isAllowForwardMessage(mMsgItem)) {
                            Toast.makeText(ComposeMessageActivity.this,
                                    R.string.forward_size_over, Toast.LENGTH_SHORT).show();
                            return false;
                        }
                        forwardMessage(mMsgItem);
                        return true;

                    case MENU_RESEND:
                        resendMessage(mMsgItem);
                        return true;

                    case MENU_VIEW_SLIDESHOW:
                        MessageUtils.viewMmsMessageAttachment(ComposeMessageActivity.this,
                                ContentUris.withAppendedId(Mms.CONTENT_URI, mMsgItem.mMsgId), null,
                                getAsyncDialog());
                        return true;

                    case MENU_VIEW_MESSAGE_DETAILS:
                        return showMessageDetails(mMsgItem);

                    case MENU_DELETE_MESSAGE: {
                        DeleteMessageListener l = new DeleteMessageListener(mMsgItem);
                        confirmDeleteDialog(l, mMsgItem.mLocked);
                        return true;
                    }
                    case MENU_DELIVERY_REPORT:
                        showDeliveryReport(mMsgItem.mMsgId, mMsgItem.mType);
                        return true;

                    case MENU_COPY_TO_SDCARD: {
                        int resId = copyMedia(mMsgItem.mMsgId) ? R.string.copy_to_sdcard_success :
                            R.string.copy_to_sdcard_fail;
                        Toast.makeText(ComposeMessageActivity.this, resId, Toast.LENGTH_SHORT).show();
                        return true;
                    }


                    case MENU_SAVE_RINGTONE: {
                        int resId = getDrmMimeSavedStringRsrc(mMsgItem.mIsDrmRingtoneWithRights,
                                saveRingtone(mMsgItem.mMsgId));
                        Toast.makeText(ComposeMessageActivity.this, resId, Toast.LENGTH_SHORT).show();
                        return true;
                    }

                    case MENU_LOCK_MESSAGE: {
                        lockMessage(mMsgItem, true);
                        return true;
                    }

                    case MENU_UNLOCK_MESSAGE: {
                        lockMessage(mMsgItem, false);
                        return true;
                    }

                    case MENU_COPY_EXTRACT_URL:
                        String copyedUrl = item.getIntent().getStringExtra("copyurl");
                        copyToClipboard(copyedUrl);
                        return true;

                    case MENU_COPY_TO_SIM: {
                        if (MessageUtils.getActivatedIccCardCount() > 1) {
                            showCopySelectDialog(mMsgItem);
                        } else if (MessageUtils.isMultiSimEnabledMms()) {
                            new Thread(new CopyToSimThread(mMsgItem,
                                    MessageUtils.isIccCardActivated(MessageUtils.SUB1) ?
                                    MessageUtils.SUB1 : MessageUtils.SUB2)).start();
                        } else {
                            new Thread(new CopyToSimThread(mMsgItem)).start();
                        }
                        return true;
                    }
                    case MENU_SELECT_COPY_MESSAGE_TEXT:
                        AdapterView.AdapterContextMenuInfo info;
                        try {
                             info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
                        } catch (ClassCastException exception) {
                            Log.e(TAG, "Bad menuInfo.", exception);
                            return false;
                        }

                        final Cursor cursor = (Cursor) mMsgListAdapter.getItem(info.position);
                        if (mMsgItem.isSms()) {
                            showSmsMessageContent(cursor);
                        } else {
                            MessageUtils.viewMmsMessageAttachment(ComposeMessageActivity.this,
                                    ContentUris.withAppendedId(Mms.CONTENT_URI, mMsgItem.mMsgId), null,
                                    getAsyncDialog());
                        }
                        return true;
                    default:
                        return false;
                }
            }
        }

    上述代码<TAG 1-1>中,调用copyMedia()方法<TAG 1-2>代码如下:

        private boolean copyMedia(long msgId) {
            boolean result = true;
            PduBody body = null;
            try {
                body = SlideshowModel.getPduBody(this,
                            ContentUris.withAppendedId(Mms.CONTENT_URI, msgId));
            } catch (MmsException e) {
                Log.e(TAG, "copyMedia can't load pdu body: " + msgId);
            }
            if (body == null) {
                return false;
            }

            int partNum = body.getPartsNum();
            for(int i = 0; i < partNum; i++) {
                PduPart part = body.getPart(i);

                // all parts have to be successful for a valid result.
                result &= copyPart(part, Long.toHexString(msgId));
            }
            return result;
       
    上述代码<TAG 1-2>中,调用copyPart()方法<TAG 1-3>代码如下:

    private boolean copyPart(PduPart part, String fallback) {
            Uri uri = part.getDataUri();
            String type = new String(part.getContentType());
            boolean isDrm = DrmUtils.isDrmType(type);
            if (isDrm) {
                type = MmsApp.getApplication().getDrmManagerClient()
                        .getOriginalMimeType(part.getDataUri());
            }
            if (!ContentType.isImageType(type)
                    && !ContentType.isVideoType(type)
                    && !ContentType.isAudioType(type)
                    && !(ContentType.TEXT_VCARD.toLowerCase().equals(type.toLowerCase()))
                    && !(ContentType.AUDIO_OGG.toLowerCase().equals(type.toLowerCase()))) {
                return true;    // we only save pictures, videos, and sounds. Skip the text parts,
                                // the app (smil) parts, and other type that we can't handle.
                                // Return true to pretend that we successfully saved the part so
                                // the whole save process will be counted a success.
            }
            InputStream input = null;
            FileOutputStream fout = null;
            try {
                input = mContentResolver.openInputStream(uri);
                if (input instanceof FileInputStream) {
                    FileInputStream fin = (FileInputStream) input;

                    byte[] location = part.getName();
                    if (location == null) {
                        location = part.getFilename();
                    }
                    if (location == null) {
                        location = part.getContentLocation();
                    }

                    String fileName;
                    if (location == null) {
                        // Use fallback name.
                        fileName = fallback;
                    } else {
                        // For locally captured videos, fileName can end up being something like this:
                        //      /mnt/sdcard/Android/data/com.android.mms/cache/.temp1.3gp
                        fileName = new String(location);
                    }
                    File originalFile = new File(fileName);
                    fileName = originalFile.getName();  // Strip the full path of where the "part" is
                                                        // stored down to just the leaf filename.
                                                        Log.d("bill","utf--"+(new String(location,"gb2312")+"--dd--"+(new String(location))));
                                                        Log.d("bill","fileName--"+fileName);
                    // Depending on the location, there may be an
                    // extension already on the name or not. If we've got audio, put the attachment
                    // in the Ringtones directory.
                    String dir = Environment.getExternalStorageDirectory() + "/"
                                    + (ContentType.isAudioType(type) ? Environment.DIRECTORY_RINGTONES :
                                        Environment.DIRECTORY_DOWNLOADS)  + "/";
                    String extension;
                    int index;
                    if ((index = fileName.lastIndexOf('.')) == -1) {
                        extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type);
                    } else {
                        extension = fileName.substring(index + 1, fileName.length());
                        fileName = fileName.substring(0, index);
                    }
                    if (isDrm) {
                        extension += DrmUtils.getConvertExtension(type);
                    }

                    // Remove leading periods. The gallery ignores files starting with a period.
                    fileName = fileName.replaceAll("^\.", "");

                    File file = getUniqueDestination(dir + fileName, extension);

                    // make sure the path is valid and directories created for this file.
                    File parentFile = file.getParentFile();
                    if (!parentFile.exists() && !parentFile.mkdirs()) {
                        Log.e(TAG, "[MMS] copyPart: mkdirs for " + parentFile.getPath() + " failed!");
                        return false;
                    }

                    fout = new FileOutputStream(file);

                    byte[] buffer = new byte[8000];
                    int size = 0;
                    while ((size=fin.read(buffer)) != -1) {
                        fout.write(buffer, 0, size);
                    }

                    // Notify other applications listening to scanner events
                    // that a media file has been added to the sd card
                    sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                            Uri.fromFile(file)));
                }
            } catch (IOException e) {
                // Ignore
                Log.e("bill", "IOException caught while opening or reading stream", e);
                return false;
            } finally {
                if (null != input) {
                    try {
                        input.close();
                    } catch (IOException e) {
                        // Ignore
                        Log.e(TAG, "IOException caught while closing stream", e);
                        return false;
                    }
                }
                if (null != fout) {
                    try {
                        fout.close();
                    } catch (IOException e) {
                        // Ignore
                        Log.e(TAG, "IOException caught while closing stream", e);
                        return false;
                    }
                }
            }
            return true;
        }

    上述代码<TAG 1-3>中,调用PduPart.java类中的getName()

         public byte[] getName() {
             return (byte[]) mPartHeader.get(P_NAME);
         }

    因此我们分析setName()方法:

         public void setName(byte[] name) {
         android.util.Log.d("bill",android.util.Log.getStackTraceString(new Throwable()));
             if(null == name) {
                 throw new NullPointerException("null content-id");
             }

             mPartHeader.put(P_NAME, name);
         }

    通过打印堆栈我们进行代码追溯:

    06-03 17:29:02.759 D/bill    ( 1320): java.lang.Throwable
    06-03 17:29:02.759 D/bill    ( 1320):     at com.google.android.mms.pdu.PduPart.setName(PduPart.java:342)
    06-03 17:29:02.759 D/bill    ( 1320):     at com.google.android.mms.pdu.PduPersister.loadParts(PduPersister.java:440)
    06-03 17:29:02.759 D/bill    ( 1320):     at com.google.android.mms.pdu.PduPersister.load(PduPersister.java:632)

    分析PduPersister.java类中的loadParts()方法<TAG 1-4>:

    private PduPart[] loadParts(long msgId) throws MmsException {
            Cursor c = SqliteWrapper.query(mContext, mContentResolver,
                    Uri.parse("content://mms/" + msgId + "/part"),
                    PART_PROJECTION, null, null, null);

            PduPart[] parts = null;

            try {
                if ((c == null) || (c.getCount() == 0)) {
                    if (LOCAL_LOGV) {
                        Log.v(TAG, "loadParts(" + msgId + "): no part to load.");
                    }
                    return null;
                }

                int partCount = c.getCount();
                int partIdx = 0;
                parts = new PduPart[partCount];
                while (c.moveToNext()) {
                    PduPart part = new PduPart();
                    Integer charset = getIntegerFromPartColumn(
                            c, PART_COLUMN_CHARSET);
                    if (charset != null) {
                        part.setCharset(charset);
                    }

                    byte[] contentDisposition = getByteArrayFromPartColumn(
                            c, PART_COLUMN_CONTENT_DISPOSITION);
                    if (contentDisposition != null) {
                        part.setContentDisposition(contentDisposition);
                    }

                    byte[] contentId = getByteArrayFromPartColumn(
                            c, PART_COLUMN_CONTENT_ID);
                    if (contentId != null) {
                        part.setContentId(contentId);
                    }

                    byte[] contentLocation = getByteArrayFromPartColumn(
                            c, PART_COLUMN_CONTENT_LOCATION);
                    if (contentLocation != null) {
                        part.setContentLocation(contentLocation);
                    }

                    byte[] contentType = getByteArrayFromPartColumn(
                            c, PART_COLUMN_CONTENT_TYPE);
                    if (contentType != null) {
                        part.setContentType(contentType);
                    } else {
                        throw new MmsException("Content-Type must be set.");
                    }

                    byte[] fileName = getByteArrayFromPartColumn(
                            c, PART_COLUMN_FILENAME);
                    if (fileName != null) {
                        part.setFilename(fileName);
                    }

                    byte[] name = getByteArrayFromPartColumn(
                            c, PART_COLUMN_NAME);
                    if (name != null) {
                        part.setName(name);
                    }


                    // Construct a Uri for this part.
                    long partId = c.getLong(PART_COLUMN_ID);
                    Uri partURI = Uri.parse("content://mms/part/" + partId);
                    part.setDataUri(partURI);

                    // For images/audio/video, we won't keep their data in Part
                    // because their renderer accept Uri as source.
                    String type = toIsoString(contentType);
                    if (!ContentType.isImageType(type)
                            && !ContentType.isAudioType(type)
                            && !ContentType.isVideoType(type)) {
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        InputStream is = null;

                        // Store simple string values directly in the database instead of an
                        // external file.  This makes the text searchable and retrieval slightly
                        // faster.
                        if (ContentType.TEXT_PLAIN.equals(type) || ContentType.APP_SMIL.equals(type)
                                || ContentType.TEXT_HTML.equals(type)) {
                            String text = c.getString(PART_COLUMN_TEXT);
                            byte [] blob = new EncodedStringValue(text != null ? text : "")
                                .getTextString();
                            baos.write(blob, 0, blob.length);
                        } else {

                            try {
                                is = mContentResolver.openInputStream(partURI);

                                byte[] buffer = new byte[256];
                                int len = is.read(buffer);
                                while (len >= 0) {
                                    baos.write(buffer, 0, len);
                                    len = is.read(buffer);
                                }
                            } catch (IOException e) {
                                Log.e(TAG, "Failed to load part data", e);
                                c.close();
                                throw new MmsException(e);
                            } finally {
                                if (is != null) {
                                    try {
                                        is.close();
                                    } catch (IOException e) {
                                        Log.e(TAG, "Failed to close stream", e);
                                    } // Ignore
                                }
                            }
                        }
                        part.setData(baos.toByteArray());
                    }
                    parts[partIdx++] = part;
                }
            } finally {
                if (c != null) {
                    c.close();
                }
            }

            return parts;
        }

    上述代码<TAG 1-4>中,从如下的代码我们可以发现,这里从数据库中取出数据,并对数据进行了编码,从上一篇博客中我们可以了解,我们已经对字节数组进行了处理,也就是说数据不再是单一的ISO_8895-1编码,而是数据的原始编码。这里则不用再对数据进行处理。

        private byte[] getByteArrayFromPartColumn(Cursor c, int columnIndex) {
            if (!c.isNull(columnIndex)) {
                return getBytes(c.getString(columnIndex));
            }
            return null;
        }

        public static byte[] getBytes(String data) {<TAG 1-5>
            try {
                return data.getBytes(CharacterSets.MIMENAME_ISO_8859_1);
            } catch (UnsupportedEncodingException e) {
                // Impossible to reach here!
                Log.e(TAG, "ISO_8859_1 must be supported!", e);
                return new byte[0];
            }
        }

    代码<TAG 1-5>修改如下,

    public static byte[] getBytes(String data) {<TAG 1-5>
            return data.getBytes(CharacterSets.MIMENAME_ISO_8859_1);
    }

    乱码问题搞定,这附件不能保存的问题,迎刃而解。

  • 相关阅读:
    k.dbtool.engine v1.0.0.5 数据访问中间件 使用说明(一)
    OPEN(SAP) UI5 学习入门系列之四:更好的入门系列-官方Walkthrough
    OPEN(SAP) UI5 学习入门系列之三:MVC (下)
    OPEN(SAP) UI5 学习入门系列之三:MVC (上)
    OPEN(SAP) UI5 学习入门系列之二: 最佳实践练习(下)
    OPEN(SAP) UI5 学习入门系列之二: 最佳实践练习(上)
    OPEN(SAP) UI5 学习入门系列之一:扫盲与热身(下)
    OPEN(SAP) UI5 学习入门系列之一:扫盲与热身(上)
    开博第一篇
    浏览器缓存
  • 原文地址:https://www.cnblogs.com/bill-technology/p/4130942.html
Copyright © 2011-2022 走看看