package com.mogujie.tt.adapter; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.annotation.SuppressLint; import android.app.Activity; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; import com.mogujie.tt.R; import com.mogujie.tt.audio.biz.AudioPlayerHandler; import com.mogujie.tt.biz.MessageHelper; import com.mogujie.tt.cache.biz.CacheHub; import com.mogujie.tt.config.SysConstant; import com.mogujie.tt.entity.MessageInfo; import com.mogujie.tt.entity.TimeTileMessage; import com.mogujie.tt.imlib.IMMessageManager; import com.mogujie.tt.imlib.IMSession; import com.mogujie.tt.imlib.service.IMService; import com.mogujie.tt.imlib.utils.IMUIHelper; import com.mogujie.tt.log.Logger; import com.mogujie.tt.ui.activity.DisplayImageActivity; import com.mogujie.tt.ui.activity.MessageActivity; import com.mogujie.tt.ui.activity.PreviewTextActivity; import com.mogujie.tt.ui.tools.BubbleImageHelper; import com.mogujie.tt.ui.tools.Emoparser; import com.mogujie.tt.ui.tools.MessageBitmapCache; import com.mogujie.tt.ui.utils.IMServiceHelper; import com.mogujie.tt.utils.CommonUtil; import com.mogujie.tt.utils.DateUtil; import com.mogujie.tt.utils.FileUtil; import com.mogujie.tt.widget.MGProgressbar; import com.mogujie.tt.widget.MessageOperatePopup; import com.mogujie.tt.widget.SpeekerToast; import com.mogujie.widget.imageview.MGWebImageView; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; import com.squareup.picasso.Picasso.LoadedFrom; /** * @Description 消息适配器 * @author Nana * @date 2014-3-15 */ public class MessageAdapter extends BaseAdapter { public static final int MESSAGE_TYPE_INVALID = -1; public static final int MESSAGE_TYPE_MINE_TETX = 0x00; public static final int MESSAGE_TYPE_MINE_IMAGE = 0x01; public static final int MESSAGE_TYPE_MINE_AUDIO = 0x02; public static final int MESSAGE_TYPE_OTHER_TEXT = 0x03; public static final int MESSAGE_TYPE_OTHER_IMAGE = 0x04; public static final int MESSAGE_TYPE_OTHER_AUDIO = 0x05; public static final int MESSAGE_TYPE_TIME_TITLE = 0x07; public static final int MESSAGE_TYPE_HISTORY_DIVIDER = 0x08; private static final int VIEW_TYPE_COUNT = 9; public static final String HISTORY_DIVIDER_TAG = "history_divider_tag"; public static Handler messageHanler = null; private Activity context = null; private LayoutInflater inflater = null; private ArrayList<Object> messageList = new ArrayList<Object>(); @SuppressWarnings("unused") private static int selectedPosition = -1; // key = msgid, value = the position in messageList // private MsgIdToPositionMap msgIndexMap = new MsgIdToPositionMap(); private volatile static HashMap<String, AnimationDrawable> audioPathAnimMap = new HashMap<String, AnimationDrawable>(); private static String playingPath = null; MessageOperatePopup currentPopupView; private boolean mHistoryFirstAdd = true;; private Logger logger = Logger.getLogger(MessageAdapter.class); private IMSession session; private IMServiceHelper imServiceHelper; public void setIMServiceHelper(IMServiceHelper imServiceHelper) { this.imServiceHelper = imServiceHelper; } public MessageAdapter(Activity cxt) { super(); // todo eric any recycle reference issue here context = cxt; if (null != context) { inflater = ((Activity) context).getLayoutInflater(); } } public void clearMsgIndexMap() { // if (null != msgIndexMap) { // msgIndexMap.clear(); // } mHistoryFirstAdd = true; } public void stopVoicePlayAnim(String path) { if (null == path) { return; } if (audioPathAnimMap.containsKey(path)) { AnimationDrawable anim = audioPathAnimMap.get(path); if (null != anim && anim.isRunning()) { anim.stop(); anim.selectDrawable(0); audioPathAnimMap.remove(path); } } if (null != playingPath && playingPath.equals(path)) { playingPath = ""; } } @Override public void notifyDataSetChanged() { // DumpUtils.dumpStacktrace(logger, "debug#notifyDataSetChanged", // false); // logger.i("debug#notifyDataSetChanged"); super.notifyDataSetChanged(); } @Override public int getCount() { if (null == messageList) { return 0; } else { return messageList.size(); } } @Override public Object getItem(int position) { if (position >= getCount() || position < 0) { return null; } return messageList.get(position); } @Override public long getItemId(int position) { return position; } public void clearItem() { messageList.clear(); } public void setSelectedPosition(int position) { selectedPosition = position; } /** * 历史消息的添加请千万走这个函数 * * @param fromStart * @param list */ public void addItem(boolean fromStart, List<MessageInfo> list) { // logger.d("debug#dump addItem fromStart msgList"); int index = 0; for (MessageInfo msgInfo : list) { // logger.d("debug#index:%d, msg:%s", index, msgInfo); ++index; } try { if (null == list || list.size() == 0) { return; } // 如果是历史消息,从头开始加 messageList.addAll(fromStart ? 0 : messageList.size(), list); // 先取出需要加进去的数据数量 final int count = list.size(); // logger.d("debug#list size:%d", count); if (fromStart) { // 因为第一次插入历史数据的时候,需要插入一条divider数据,所以后移的偏移量是count + 1 // updatePositonSeqMap(0, mHistoryFirstAdd ? count + 1 : count); // msgIndexMap.fix(0, count); } // 从加进去的那个info开始,赋值各条消息的状态 for (int i = 0; i < count; i++) { MessageInfo info = (MessageInfo) list.get(i); if (null == info) { continue; } // msgIndexMap.put(info.msgId, fromStart ? i : count + i); } int position = count - 1; while (position >= 0) { Object obj = messageList.get(position); if (!(obj instanceof MessageInfo)) { position--; continue; } MessageInfo preInfo = null; for (int i = position - 1; i >= 0; i--) { if (messageList.get(i) instanceof MessageInfo) { preInfo = (MessageInfo) messageList.get(i); break; } } MessageInfo info = (MessageInfo) obj; if (DateUtil.needDisplayTime(null == preInfo ? null : preInfo.getMsgCreateTime(), info.getMsgCreateTime())) { // 如果当前位置已经有了time title,就不需要再加了 if (!(messageList.get(position) instanceof TimeTileMessage)) { TimeTileMessage timeTile = new TimeTileMessage(); timeTile.setTime(info.getMsgCreateTime()); // 更新一下状态位置映射 // msgIndexMap.fix(position, 1); messageList.add(position, timeTile); } } position--; } // if (mHistoryFirstAdd) { // mHistoryFirstAdd = false; // } } catch (Exception e) { logger.e(e.getMessage()); } } public void setSession(IMSession session) { logger.d("chat#seSession"); this.session = session; } /** * 这个函数只能从末尾添加 * * @param fromStart * @param item * */ public void addItem(MessageInfo info) { logger.d("chat#addItem"); try { if (null == info || messageList.contains(info)) { logger.d("chat#already has this item"); return; } messageList.add(info); // msgIndexMap.put(info.msgId, messageList.size() - 1); final int count = messageList.size(); MessageInfo preInfo = null; for (int i = count - 2; i >= 0; i--) { if (messageList.get(i) instanceof MessageInfo) { preInfo = (MessageInfo) messageList.get(i); break; } } if (DateUtil.needDisplayTime(null == preInfo ? null : preInfo.getMsgCreateTime(), info.getMsgCreateTime())) { TimeTileMessage timeTitle = new TimeTileMessage(); timeTitle.setTime(info.getMsgCreateTime()); // msgIndexMap.fix(count - 1, 1); messageList.add(count - 1, timeTitle); } logger.d("chat#finish add item"); } catch (Exception e) { logger.e("chat#find exception:%s", e.getMessage()); logger.e(e.getMessage()); } } private MessageInfo getMsgInfo(String msgId) { for (Object obj : messageList) { if (!(obj instanceof MessageInfo)) { continue; } MessageInfo msgInfo = (MessageInfo) obj; if (msgInfo.msgId.equals(msgId)) { return msgInfo; } } return null; } /** * @Description 由MessageInfo对象修改消息状态(可修改图片文本消息) * @param messageInfo * @param state */ public void updateMessageState(MessageInfo messageInfo, int state) { // logger.d("debug#updateMessageState"); if (null == messageInfo) return; try { if (state < SysConstant.MESSAGE_STATE_UNLOAD || state > SysConstant.MESSAGE_STATE_FINISH_FAILED || null == context) return; String msgId = messageInfo.msgId; MessageInfo msgInfo = getMsgInfo(msgId); if (msgInfo == null) { logger.e("chat#error can't find msgInfo:%s", msgId); return; } msgInfo.setMsgLoadState(state); // CacheHub.getInstance().updateMsgStatus(msgId, state); if (messageInfo.getDisplayType() == SysConstant.DISPLAY_TYPE_IMAGE) { logger.d("pic#this is image"); String savePath = ""; if (null != messageInfo.getSavePath()) { savePath = messageInfo.getSavePath(); } logger.d("pic#setsavepath:%s", savePath); msgInfo.setSavePath(savePath); msgInfo.setMsgReadStatus(SysConstant.MESSAGE_ALREADY_READ); // CacheHub.getInstance().updateMsgImageSavePath(messageInfo.msgId, // savePath); if (imServiceHelper != null) { IMService imService = imServiceHelper.getIMService(); if (imService != null) { imService.getDbManager().updatePictureMessagePath(messageInfo); } } } notifyDataSetChanged(); } catch (Exception e) { logger.e(e.getMessage()); } } /** * @Description 由消息id去修改消息状态(用于只有id的情况) * @param msgId * @param state */ public void updateItemState(String msgId, int state) { try { String stackTraceString = Log.getStackTraceString(new Throwable()); stackTraceString.replaceAll("\n", "###"); // logger.d("debug#updateItemState stack:%s", stackTraceString); MessageInfo msgInfo = getMsgInfo(msgId); if (msgInfo == null) { logger.e("chat#error can't find msgInfo:%s", msgId); return; } if (null != CacheHub.getInstance()) { // CacheHub.getInstance().updateMsgStatus(msgId, state); } msgInfo.setMsgLoadState(state); // logger.d("debug#updateItemState, msg:%s", msgInfo); notifyDataSetChanged(); } catch (Exception e) { logger.e(e.getMessage()); } } public void updateItemSavePath(String msgId, String path) { try { MessageInfo msgInfo = getMsgInfo(msgId); if (msgInfo == null) { logger.e("chat#error can't find msgInfo:%s", msgId); return; } msgInfo.setSavePath(path); notifyDataSetChanged(); } catch (Exception e) { logger.e(e.getMessage()); } } @Override public View getView(int position, View convertView, final ViewGroup parent) { try { final int type = getItemViewType(position); // 所有需要被赋值的holder都是基于MessageHolderBase的 MessageHolderBase holder = null; if (null == convertView && null != inflater) { if (type == MESSAGE_TYPE_TIME_TITLE) { convertView = inflater.inflate(R.layout.tt_message_title_time, parent, false); // 这货是个特殊情况 TimeTitleMessageHodler ttHodler = new TimeTitleMessageHodler(); convertView.setTag(ttHodler); ttHodler.time_title = (TextView) convertView.findViewById(R.id.time_title); } else if (type == MESSAGE_TYPE_HISTORY_DIVIDER) { // 这货只可能有一条,所以不用缓存了 convertView = inflater.inflate(R.layout.tt_history_divider_item, parent, false); } else if (type == MESSAGE_TYPE_MINE_TETX) { convertView = inflater.inflate(R.layout.tt_mine_text_message_item, parent, false); holder = new TextMessageHolder(); convertView.setTag(holder); fillTextMessageHolder((TextMessageHolder) holder, convertView); } else if (type == MESSAGE_TYPE_MINE_IMAGE) { convertView = inflater.inflate(R.layout.tt_mine_image_message_item, parent, false); holder = new ImageMessageHolder(); convertView.setTag(holder); fillImageMessageHolder((ImageMessageHolder) holder, convertView); } else if (type == MESSAGE_TYPE_MINE_AUDIO) { logger.d("chat#start inflating audio item"); convertView = inflater.inflate(R.layout.tt_mine_audio_message_item, parent, false); logger.d("chat#finish inflating audio item"); holder = new AudioMessageHolder(); convertView.setTag(holder); fillAudioMessageHolder((AudioMessageHolder) holder, convertView); logger.d("chat#after fillAudioMessageHolder"); } else if (type == MESSAGE_TYPE_OTHER_TEXT) { convertView = inflater.inflate(R.layout.tt_other_text_message_item, parent, false); holder = new TextMessageHolder(); convertView.setTag(holder); fillTextMessageHolder((TextMessageHolder) holder, convertView); } else if (type == MESSAGE_TYPE_OTHER_IMAGE) { convertView = inflater.inflate(R.layout.tt_other_image_message_item, parent, false); holder = new ImageMessageHolder(); convertView.setTag(holder); fillImageMessageHolder((ImageMessageHolder) holder, convertView); } else if (type == MESSAGE_TYPE_OTHER_AUDIO) { convertView = inflater.inflate(R.layout.tt_other_audio_message_item, parent, false); holder = new AudioMessageHolder(); convertView.setTag(holder); fillAudioMessageHolder((AudioMessageHolder) holder, convertView); } } else { if (type != MESSAGE_TYPE_TIME_TITLE) { holder = (MessageHolderBase) convertView.getTag(); } } // 这些都是不需要被赋值的 if (type == MESSAGE_TYPE_HISTORY_DIVIDER || type == MESSAGE_TYPE_INVALID) { return convertView; } if (type == MESSAGE_TYPE_TIME_TITLE) { TimeTileMessage msg = (TimeTileMessage) messageList.get(position); ((TimeTitleMessageHodler) convertView.getTag()).time_title.setText(DateUtil.getTimeDiffDesc(msg.getTime())); return convertView; } final MessageInfo info = (MessageInfo) messageList.get(position); // logger.d("debug#getview MessageInfo position:%d, info:%s", // position, info); // DumpUtils.dumpStacktrace(logger, "debug#getview", false); IMUIHelper.setMessageOwnerAvatar(logger, session, info, holder.portrait); IMUIHelper.setMessageOwnerName(logger, session, info, holder.name); final View baseView = getBaseViewForMenu(holder, info); if (info.getMsgLoadState() == SysConstant.MESSAGE_STATE_FINISH_FAILED) { holder.messageFailed.setVisibility(View.VISIBLE); holder.messageFailed.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { logger.d("debug#onClick, msg:%s", info); if (!info.isMy() && info.isImage()) { logger.d("debug#pic#found failed receiving image message"); updateItemState(info.msgId, SysConstant.MESSAGE_STATE_UNLOAD); } int menuType = getMenuType(info); if (menuType > 0) { // logger.d("debug#showMenu MessageInfo:%s", info); showMenu(context, menuType, parent, info, baseView); } } }); } else { holder.messageFailed.setVisibility(View.GONE); } if (info.getMsgLoadState() == SysConstant.MESSAGE_STATE_LOADDING && !info.isImage()) { holder.loadingProgressBar.setVisibility(View.VISIBLE); } else { holder.loadingProgressBar.setVisibility(View.GONE); } if (type == MESSAGE_TYPE_MINE_TETX || type == MESSAGE_TYPE_OTHER_TEXT) { handleTextMessage((TextMessageHolder) holder, info, parent); } else if (type == MESSAGE_TYPE_MINE_IMAGE) { handleImageMessage((ImageMessageHolder) holder, info, position, true, parent); } else if (type == MESSAGE_TYPE_OTHER_IMAGE) { handleImageMessage((ImageMessageHolder) holder, info, position, false, parent); } else if (type == MESSAGE_TYPE_MINE_AUDIO) { handleAudioMessage((AudioMessageHolder) holder, info, true, parent, position); } else if (type == MESSAGE_TYPE_OTHER_AUDIO) { handleAudioMessage((AudioMessageHolder) holder, info, false, parent, position); } return convertView; } catch (Exception e) { if (null != e && null != logger) { logger.e("chat#%s", e); } return null; } } @Override public int getItemViewType(int position) { // logger.d("chat#getItemViewType -> position:%d", position); try { if (position >= messageList.size()) { return MESSAGE_TYPE_INVALID; } Object obj = messageList.get(position); if (obj instanceof TimeTileMessage) { return MESSAGE_TYPE_TIME_TITLE; } else if (obj instanceof String && obj.equals(HISTORY_DIVIDER_TAG)) { return MESSAGE_TYPE_HISTORY_DIVIDER; } else { MessageInfo info = (MessageInfo) obj; if (info.getMsgFromUserId().equals(CacheHub.getInstance().getLoginUserId())) { if (info.getDisplayType() == SysConstant.DISPLAY_TYPE_TEXT) { return MESSAGE_TYPE_MINE_TETX; } else if (info.getDisplayType() == SysConstant.DISPLAY_TYPE_IMAGE) { return MESSAGE_TYPE_MINE_IMAGE; } else if (info.getDisplayType() == SysConstant.DISPLAY_TYPE_AUDIO) { return MESSAGE_TYPE_MINE_AUDIO; } } else { if (info.getDisplayType() == SysConstant.DISPLAY_TYPE_TEXT) { return MESSAGE_TYPE_OTHER_TEXT; } else if (info.getDisplayType() == SysConstant.DISPLAY_TYPE_IMAGE) { return MESSAGE_TYPE_OTHER_IMAGE; } else if (info.getDisplayType() == SysConstant.DISPLAY_TYPE_AUDIO) { return MESSAGE_TYPE_OTHER_AUDIO; } } } return MESSAGE_TYPE_INVALID; } catch (Exception e) { logger.e(e.getMessage()); return MESSAGE_TYPE_INVALID; } } private int getMenuType(MessageInfo msg) { if (msg.getDisplayType() == SysConstant.DISPLAY_TYPE_TEXT) { return SysConstant.POPUP_MENU_TYPE_TEXT; } else if (msg.getDisplayType() == SysConstant.DISPLAY_TYPE_IMAGE) { return SysConstant.POPUP_MENU_TYPE_IMAGE; } else if (msg.getDisplayType() == SysConstant.DISPLAY_TYPE_AUDIO) { return SysConstant.POPUP_MENU_TYPE_AUDIO; } else { return -1; } } private View getBaseViewForMenu(MessageHolderBase holder, MessageInfo msg) { if (msg.getDisplayType() == SysConstant.DISPLAY_TYPE_TEXT) { return ((TextMessageHolder) holder).message_content; } else if (msg.getDisplayType() == SysConstant.DISPLAY_TYPE_IMAGE) { return ((ImageMessageHolder) holder).message_layout; } else if (msg.getDisplayType() == SysConstant.DISPLAY_TYPE_AUDIO) { return ((AudioMessageHolder) holder).message_layout; } else { return null; } } @Override public int getViewTypeCount() { return VIEW_TYPE_COUNT; } public void hidePopup() { if (currentPopupView != null) { currentPopupView.dismiss(); } } private void fillBaseMessageholder(MessageHolderBase holder, View convertView) { holder.portrait = (MGWebImageView) convertView.findViewById(R.id.user_portrait); holder.messageFailed = (ImageView) convertView.findViewById(R.id.message_state_failed); holder.loadingProgressBar = (ProgressBar) convertView.findViewById(R.id.progressBar1); holder.name = (TextView) convertView.findViewById(R.id.name); logger.d("name#holder.name:%s", holder.name); } private void fillTextMessageHolder(TextMessageHolder holder, View convertView) { fillBaseMessageholder(holder, convertView); holder.message_content = (TextView) convertView.findViewById(R.id.message_content); } private void fillImageMessageHolder(ImageMessageHolder holder, View convertView) { fillBaseMessageholder(holder, convertView); holder.message_layout = convertView.findViewById(R.id.message_layout); holder.message_image = (ImageView) convertView.findViewById(R.id.message_image); holder.image_progress = (MGProgressbar) convertView.findViewById(R.id.tt_image_progress); holder.image_progress.setShowText(false); } private void fillAudioMessageHolder(AudioMessageHolder holder, View convertView) { fillBaseMessageholder(holder, convertView); holder.message_layout = convertView.findViewById(R.id.message_layout); holder.audio_antt_view = convertView.findViewById(R.id.audio_antt_view); holder.audio_duration = (TextView) convertView.findViewById(R.id.audio_duration); holder.audio_unread_notify = convertView.findViewById(R.id.audio_unread_notify); } private void handleTextMessage(final TextMessageHolder holder, final MessageInfo info, final View parent) { if (null == holder || null == info) { return; } holder.message_content.setText(Emoparser.getInstance(context).emoCharsequence(info.getMsgContent())); holder.message_content.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { showMenu(context, SysConstant.POPUP_MENU_TYPE_TEXT, parent, info, holder.message_content); return true; } }); holder.message_content.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View arg0) { CommonUtil.skipLink(context, info.getMsgContent()); } }); holder.message_content.setOnTouchListener(new onDoubleClick(info.getMsgContent())); } /** * @Description 处理图片消息 * @param holder * @param info * @param position * @param isMine * @param parent */ private void handleImageMessage(final ImageMessageHolder holder, final MessageInfo info, int position, boolean isMine, final View parent) { logger.d("chat#handleImageMessage"); try { boolean setBackground = false;// 图片加载失败时是否显示背景 if (null == holder || null == info) return; if (isMine) { logger.d("chat#is mine"); holder.message_image.setOnClickListener(new BtnImageListener(info, position, isMine)); } String path = info.getSavePath(); logger.d("chat#save path is:%s", path); @SuppressWarnings("unused") String url = info.getUrl(); logger.d("chat#url:%s", url); Bitmap bmp = null; if (!TextUtils.isEmpty(path)) { bmp = MessageBitmapCache.getInstance().get(path); if (isMine) { bmp = BubbleImageHelper.getInstance(context).getBubbleImageBitmap(bmp, R.drawable.tt_mine_image_default_bk); } else { bmp = BubbleImageHelper.getInstance(context).getBubbleImageBitmap(bmp, R.drawable.tt_other_image_default_bk); } } int msgLoadState = info.getMsgLoadState(); logger.d("chat#msgloadState:%d, msgId:%s, msg:%s", msgLoadState, info.msgId, info); switch (msgLoadState) { case SysConstant.MESSAGE_STATE_UNLOAD : { logger.d("chat#pic#MESSAGE_STATE_UNLOAD"); holder.message_image.setImageResource(R.drawable.tt_default_message_image); setBackground = true; holder.image_progress.showProgress(); if (!isMine) { logger.d("chat#pic#not mine, need donwload"); downLoadImage(info); } else { holder.message_image.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); holder.message_layout.setBackgroundResource(0); holder.message_image.setImageBitmap(bmp); holder.image_progress.hideProgress(); setBackground = false; } } break; case SysConstant.MESSAGE_STATE_LOADDING : { logger.d("chat#pic#MESSAGE_STATE_LOADDING"); if (null != bmp) { holder.message_image.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); holder.message_layout.setBackgroundResource(0); holder.message_image.setImageBitmap(bmp); setBackground = false; } else { holder.message_image.setImageResource(R.drawable.tt_default_message_image); setBackground = true; } holder.image_progress.showProgress(); } break; case SysConstant.MESSAGE_STATE_FINISH_SUCCESSED : { logger.d("chat#pic#MESSAGE_STATE_FINISH_SUCCESSED"); if (null != bmp) { holder.message_image.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); holder.message_layout.setBackgroundResource(0); holder.message_image.setImageBitmap(bmp); if (!isMine) { holder.message_image.setOnClickListener(new BtnImageListener(info, position, isMine)); } setBackground = false; } else { holder.message_image.setImageResource(R.drawable.tt_default_message_error_image); setBackground = true; } holder.image_progress.hideProgress(); } break; case SysConstant.MESSAGE_STATE_FINISH_FAILED : { holder.message_image.setOnClickListener(new BtnImageListener(info, position, isMine)); if (null != bmp) { holder.message_image.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); holder.message_layout.setBackgroundResource(0); holder.message_image.setImageBitmap(bmp); setBackground = false; } else { holder.message_image.setImageResource(R.drawable.tt_default_message_error_image); setBackground = true; } holder.image_progress.hideProgress(); } break; default : { holder.message_image.setImageResource(R.drawable.tt_default_message_error_image); setBackground = true; holder.image_progress.hideProgress(); } break; } if (setBackground) { FrameLayout.LayoutParams imageLayout = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT); if (isMine) { holder.message_layout.setBackgroundResource(R.drawable.tt_mine_item_bg); imageLayout.rightMargin = 9; } else { holder.message_layout.setBackgroundResource(R.drawable.tt_other_default_image_bk); imageLayout.leftMargin = 9; } imageLayout.gravity = Gravity.CENTER; holder.message_image.setLayoutParams(imageLayout); } holder.message_image.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { showMenu(context, SysConstant.POPUP_MENU_TYPE_IMAGE, parent, info, holder.message_layout); return true; } }); } catch (Exception e) { logger.e(e.getMessage()); } } /** * @Description 处理语音消息 * @param holder * @param info * @param isMine * @param parent * @param position */ private void handleAudioMessage(final AudioMessageHolder holder, final MessageInfo info, boolean isMine, final View parent, int position) { logger.d("chat#handleAudioMessage"); try { holder.message_layout.setOnClickListener(new BtnImageListener(info, position, isMine)); if (null != info.getSavePath()) { holder.audio_antt_view.setBackgroundResource(isMine ? R.anim.tt_voice_play_mine : R.anim.tt_voice_play_other); AnimationDrawable animationDrawable = (AnimationDrawable) holder.audio_antt_view.getBackground(); if (null != playingPath && playingPath.equals(info.getSavePath())) { animationDrawable.start(); } else { if (animationDrawable.isRunning()) { animationDrawable.stop(); animationDrawable.selectDrawable(0); } } if (info.getMsgReadStatus() < SysConstant.MESSAGE_DISPLAYED && !isMine) { holder.audio_unread_notify.setVisibility(View.VISIBLE); } else { holder.audio_unread_notify.setVisibility(View.GONE); } holder.audio_duration.setText(String.valueOf(info.getPlayTime()) + '"'); // holder.message_layout // .setOnLongClickListener(new View.OnLongClickListener() { // // @Override // public boolean onLongClick(View v) { // showMenu(context, SysConstant.POPUP_MENU_TYPE_AUDIO, parent, // info, // holder.message_layout); // return true; // } // }); RelativeLayout.LayoutParams layoutParam = new RelativeLayout.LayoutParams(CommonUtil.getAudioBkSize(info.getPlayTime(), context), LayoutParams.WRAP_CONTENT); holder.message_layout.setLayoutParams(layoutParam); if (isMine) { layoutParam.addRule(RelativeLayout.RIGHT_OF, R.id.audio_duration); RelativeLayout.LayoutParams param = (android.widget.RelativeLayout.LayoutParams) holder.audio_duration.getLayoutParams(); param.addRule(RelativeLayout.RIGHT_OF, R.id.message_state_failed); } } logger.d("chat#finish handleAudioMessage"); } catch (Exception e) { logger.d("chat#find exception:%s", e.getMessage()); logger.e(e.getMessage()); } } class BtnImageListener implements OnClickListener { private MessageInfo msgInfo = null; private int position = 0; private boolean isMine = false; public BtnImageListener(MessageInfo msg, int p, boolean me) { this.msgInfo = msg; this.position = p; this.isMine = me; } @Override public void onClick(View v) { try { if (msgInfo.getDisplayType() == SysConstant.DISPLAY_TYPE_AUDIO) { if (!new File(msgInfo.getSavePath()).exists()) { Toast.makeText(context, context.getResources().getString(R.string.notfound_audio_file), Toast.LENGTH_LONG).show(); return; } if (msgInfo.getMsgReadStatus() < SysConstant.MESSAGE_DISPLAYED) { logger.d("chat#audio#set audio meessage read status"); updateItemReadState(msgInfo.msgId, SysConstant.MESSAGE_DISPLAYED); IMService imService = imServiceHelper.getIMService(); if (imService != null) { msgInfo.setMsgReadStatus(SysConstant.MESSAGE_DISPLAYED); imService.getDbManager().updateMessageContent(msgInfo); } } if (AudioPlayerHandler.getInstance().isPlaying()) { AudioPlayerHandler.getInstance().stopPlayer(); if (playingPath.equals(msgInfo.getSavePath())) { return; } } final AnimationDrawable animationDrawable = (AnimationDrawable) v.findViewById(R.id.audio_antt_view).getBackground(); audioPathAnimMap.put(msgInfo.getSavePath(), animationDrawable); playingPath = msgInfo.getSavePath(); // 延迟播放 Thread myThread = new Thread() { public void run() { try { Thread.sleep(500); AudioPlayerHandler.getInstance().startPlay(msgInfo.getSavePath()); animationDrawable.start(); } catch (Exception e) { e.printStackTrace(); logger.e(e.toString()); } } }; myThread.start(); } else if (msgInfo.getDisplayType() == SysConstant.DISPLAY_TYPE_IMAGE) { if (msgInfo.getMsgLoadState() == SysConstant.MESSAGE_STATE_FINISH_FAILED && !isMine) { if (FileUtil.isSdCardAvailuable()) { updateItemState(msgInfo.msgId, SysConstant.MESSAGE_STATE_UNLOAD); } else { Toast.makeText(context, context.getString(R.string.sdcard_unavaluable), Toast.LENGTH_LONG).show(); } } else { // msgIndexMap.put(msgInfo.msgId, position); Intent i = new Intent(context, DisplayImageActivity.class); Bundle bundle = new Bundle(); bundle.putSerializable(SysConstant.CUR_MESSAGE, msgInfo); bundle.putBoolean("ISMINE", isMine); i.putExtras(bundle); context.startActivity(i); context.overridePendingTransition(R.anim.tt_image_enter, R.anim.tt_stay); } } } catch (Exception e) { logger.e(e.getMessage()); } } } private static class MessageHolderBase { /** * 头像 */ MGWebImageView portrait; /** * 消息状态 */ ImageView messageFailed; ProgressBar loadingProgressBar; TextView name; } private static class TextMessageHolder extends MessageHolderBase { /** * 文字消息体 */ TextView message_content; } private static class ImageMessageHolder extends MessageHolderBase { /** * 可点击的view */ View message_layout; /** * 图片消息体 */ ImageView message_image; /** * 图片状态指示 */ MGProgressbar image_progress; } private static class AudioMessageHolder extends MessageHolderBase { /** * 可点击的消息体 */ View message_layout; /** * 播放动画的view */ View audio_antt_view; /** * 指示语音是否被播放 */ View audio_unread_notify; /** * 语音时长 */ TextView audio_duration; } private static class TimeTitleMessageHodler { TextView time_title; } /** * @Description 显示菜单 * @param cxt * @param listener * @param Parent * @param msg */ private void showMenu(Context cxt, int menuType, View parent, MessageInfo msg, View layout) { boolean bIsSelf = msg.getMsgFromUserId().equals(CacheHub.getInstance().getLoginUserId()); OperateItemClickListener listener = new OperateItemClickListener(menuType); listener.setMessageInfo(msg); MessageOperatePopup popupView = new MessageOperatePopup(context, parent); popupView.setOnItemClickListener(listener); currentPopupView = popupView; boolean bResend = msg.getMsgLoadState() == SysConstant.MESSAGE_STATE_FINISH_FAILED; popupView.show(layout, menuType, bResend, bIsSelf); } private class OperateItemClickListener implements MessageOperatePopup.OnItemClickListener { private MessageInfo mMsgInfo; /* * type = 1 为文本 type = 2 为图片 type = 3 为语音 */ private int mType; public OperateItemClickListener(int nType) { this.mType = nType; } public void setMessageInfo(MessageInfo msgInfo) { // logger.d("debug#setMessageInfo msgInfo:%s, this:%s", msgInfo, // this); mMsgInfo = msgInfo; } @SuppressWarnings("deprecation") @SuppressLint("NewApi") @Override public void onCopyClick() { try { ClipboardManager manager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); logger.d("menu#onCopyClick content:%s", mMsgInfo.getMsgContent()); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { ClipData data = ClipData.newPlainText("data", mMsgInfo.getMsgContent()); manager.setPrimaryClip(data); } else { manager.setText(mMsgInfo.getMsgContent()); } } catch (Exception e) { logger.e(e.getMessage()); } } @Override public void onResendClick() { try { if (mType == SysConstant.POPUP_MENU_TYPE_TEXT || mType == SysConstant.POPUP_MENU_TYPE_AUDIO) { if (mMsgInfo.getDisplayType() == SysConstant.DISPLAY_TYPE_AUDIO) { if (null == mMsgInfo.getAudioContent()) { MessageHelper.setMsgAudioContent(mMsgInfo); } } } else if (mType == SysConstant.POPUP_MENU_TYPE_IMAGE) { logger.d("pic#resend"); mMsgInfo.setMsgLoadState(SysConstant.MESSAGE_STATE_LOADDING); updateItemState(mMsgInfo.msgId, SysConstant.MESSAGE_STATE_LOADDING); } resendMsg(mMsgInfo.msgId); } catch (Exception e) { logger.e("chat#exception:" + e.toString()); } } private void resendMsg(String msgId) { MessageInfo msgInfo = getMsgInfo(msgId); if (msgInfo == null) { logger.d("chat#resend#getMsgInfo failed.id:%s", msgId); return; } IMService imService = imServiceHelper.getIMService(); if (imService != null) { imService.getMessageManager().resendMessage(msgInfo); } } @Override public void onSpeakerClick() { if (MessageActivity.getAudioMode() == SysConstant.AUDIO_PLAY_MODE_NORMAL) { MessageActivity.setAudioMode(SysConstant.AUDIO_PLAY_MODE_IN_CALL); SpeekerToast.show(context, context.getText(R.string.audio_in_call), Toast.LENGTH_SHORT); } else { MessageActivity.setAudioMode(SysConstant.AUDIO_PLAY_MODE_NORMAL); SpeekerToast.show(context, context.getText(R.string.audio_in_speeker), Toast.LENGTH_SHORT); } } } /** * @Description 下载图片信息 * @param messageInfo */ private void downLoadImage(MessageInfo messageInfo) { try { if (null == messageInfo || messageInfo.getMsgLoadState() == SysConstant.MESSAGE_STATE_FINISH_SUCCESSED || messageInfo.getMsgLoadState() == SysConstant.MESSAGE_STATE_LOADDING) return; if (null == context) return; messageInfo.setMsgLoadState(SysConstant.MESSAGE_STATE_LOADDING); updateItemState(messageInfo.msgId, SysConstant.MESSAGE_STATE_LOADDING); // todo eric final String smallImageUrl = SysConstant.DOWNLOAD_IMAGE_URL_REPFIX + messageInfo.getUrl();// StringUtil.getSmallerImageLink(messageInfo.getUrl()); logger.d("chat#pic#download image ulr:%s", smallImageUrl); String smallImagePath = CommonUtil.getMd5Path(smallImageUrl, SysConstant.FILE_SAVE_TYPE_IMAGE); logger.d("chat#pic#image save path:%s", smallImagePath); messageInfo.setSavePath(smallImagePath); File myFile = new File(smallImagePath); if (myFile.exists()) { logger.d("chat#pic#image file already exists"); updateMessageState(messageInfo, SysConstant.MESSAGE_STATE_FINISH_SUCCESSED); return; } final MessageInfo messageInfoFinal = messageInfo; ImageLoader.getInstance().loadImage(smallImageUrl, null, null, new SimpleImageLoadingListener() { //message_image @Override public void onLoadingComplete(String imageUri, View view, Bitmap bitmap) { logger.d("chat#pic#icon onLoadingComplete"); //holder.image.setImageBitmap(loadedImage); logger.d("chat#pic#onBitmapLoaded"); String smallImagePath = CommonUtil.getMd5Path(smallImageUrl, SysConstant.FILE_SAVE_TYPE_IMAGE); File myFile = new File(smallImagePath); if (myFile.exists()) { logger.d("chat#pic#image already exists, no need to save"); return; } BufferedOutputStream bos = null; try { if (null != bitmap) { FileOutputStream fout = new FileOutputStream(myFile); bos = new BufferedOutputStream(fout); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); bos.flush(); bos.close(); bos = null; logger.d("chat#pic#save image ok"); updateMessageState(messageInfoFinal, SysConstant.MESSAGE_STATE_FINISH_SUCCESSED); } } catch (Exception e) { logger.e("chat#pic#downloading image got exception:%s", e.getMessage()); } finally { try { if (null != bos) { bos.flush(); bos.close(); } } catch (IOException e) { e.printStackTrace(); } } } @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) { logger.d("chat#pic#icon onLoadingFailed"); logger.d("chat#pic#onBitmapFailed"); updateMessageState(messageInfoFinal, SysConstant.MESSAGE_STATE_FINISH_FAILED); logger.d("download failed"); } }); // MGWebImageView.fetchBitmap(context, smallImageUrl, new MGWebImageView.TargetCallback() { // @Override // public void onPrepareLoad(Drawable placeHolderDrawable) { // } // // @Override // public void onBitmapLoaded(Bitmap bitmap, LoadedFrom from) { // logger.d("chat#pic#onBitmapLoaded"); // String smallImagePath = CommonUtil.getMd5Path(smallImageUrl, SysConstant.FILE_SAVE_TYPE_IMAGE); // File myFile = new File(smallImagePath); // if (myFile.exists()) { // logger.d("chat#pic#image already exists, no need to save"); // return; // } // BufferedOutputStream bos = null; // try { // if (null != bitmap) { // FileOutputStream fout = new FileOutputStream(myFile); // bos = new BufferedOutputStream(fout); // bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); // bos.flush(); // bos.close(); // bos = null; // logger.d("chat#pic#save image ok"); // updateMessageState(messageInfoFinal, SysConstant.MESSAGE_STATE_FINISH_SUCCESSED); // } // } catch (Exception e) { // logger.e("chat#pic#downloading image got exception:%s", e.getMessage()); // } finally { // try { // if (null != bos) { // bos.flush(); // bos.close(); // } // } catch (IOException e) { // e.printStackTrace(); // // } // } // } // // @Override // public void onBitmapFailed(Drawable errorDrawable) { // logger.d("chat#pic#onBitmapFailed"); // updateMessageState(messageInfoFinal, SysConstant.MESSAGE_STATE_FINISH_FAILED); // logger.d("download failed"); // } // }); } catch (Exception e) { logger.e(e.getMessage()); } } /** * @Description 更新消息的已读状态 * @param msgId * @param readStatus */ private void updateItemReadState(String msgId, int readStatus) { try { MessageInfo msgInfo = getMsgInfo(msgId); if (msgInfo == null) { logger.e("chat#error can't find msgInfo:%s", msgId); return; } msgInfo.setMsgReadStatus(readStatus); // CacheHub.getInstance().updateMsgReadStatus(msgId, readStatus); notifyDataSetChanged(); } catch (Exception e) { logger.e(e.getMessage()); } } /** * @Description 添加历史分隔线 */ public void addHistoryDivideTag() { try { if (!mHistoryFirstAdd) { return; } mHistoryFirstAdd = false; // msgIndexMap.fix(0, 1); messageList.add(0, HISTORY_DIVIDER_TAG); } catch (Exception e) { logger.e(e.getMessage()); } } /** * @Description 获取正在播放语音的路径 * @return */ public static String GetPlayingPath() { return playingPath; } /** * @Description 判断是否正在播放语音 * @return */ public boolean isAudioPlaying() { if (TextUtils.isEmpty(playingPath)) { return false; } else { return true; } } /** * @Description 双击事件 * @author Nana * @date 2014-7-30 */ class onDoubleClick implements View.OnTouchListener { int count = 0; int firClick = 0; int secClick = 0; String content = null; private onDoubleClick(String txt) { content = txt; } @Override public boolean onTouch(View v, MotionEvent event) { if (MotionEvent.ACTION_DOWN == event.getAction()) { count++; if (count == 1) { firClick = (int) System.currentTimeMillis(); } else if (count == 2) { secClick = (int) System.currentTimeMillis(); if (secClick - firClick < 1000) { if (v.getId() == R.id.message_content) { Intent intent = new Intent(context, PreviewTextActivity.class); intent.putExtra(SysConstant.PREVIEW_TEXT_CONTENT, content); context.startActivity(intent); } } count = 0; firClick = 0; secClick = 0; } } return false; } } }