public class ChatInfoDao {

	private static final String LOGTAG = LogUtil.makeLogTag(ChatInfoDao.class);

	private ChatInfoDBOpenHelper helper;

	public ChatInfoDao(Context context) {
		helper = new ChatInfoDBOpenHelper(context);
	}

	/**
	 * 添加一条聊天数据
	 * 
	 * @param entity 聊天数据bean
	 */
	public void add(ChatMsgEntity entity) {
		SQLiteDatabase db = helper.getWritableDatabase();
		ContentValues values = new ContentValues();
		values.put("time", String.valueOf(entity.getTime()));
		String is_show_time;
		if (entity.isShowTime()) {
			is_show_time = "1";
		} else {
			is_show_time = "0";
		}
		values.put("is_show_time", is_show_time);
		values.put("user_name", entity.getUserName());
		values.put("user_img", entity.getUserImg());
		values.put("text_msg", entity.getTextMsg());
		values.put("img_msg", entity.getImgMsg());
		values.put("voice_msg", entity.getVoiceMsg());
		values.put("msg_type", String.valueOf(entity.getMsgType()));
		String is_me_msg;
		if (entity.isMeMsg()) {
			is_me_msg = "1";
		} else {
			is_me_msg = "0";
		}
		values.put("is_me_msg", is_me_msg);
		db.insert(ChatInfoDBOpenHelper.TABLE_NAME, null, values);
		db.close();
	}

	/**
	 * 删除一条聊天数据
	 * 
	 * @param id
	 */
	public void delete(String id) {
		SQLiteDatabase db = helper.getWritableDatabase();
		db.delete(ChatInfoDBOpenHelper.TABLE_NAME, "_id=?", new String[] { id });
		db.close();
	}

	/**
	 * 查询部分的聊天数据
	 * 
	 * @param maxNumber 最多返回多少条数据
	 * @param startIndex 从哪个位置开始获取数据
	 * @return
	 */
	public List<ChatMsgEntity> findPart(int maxNumber, int startIndex) {
		SystemClock.sleep(300);
		SQLiteDatabase db = helper.getWritableDatabase();
		//select _id,location,areacode from mob_location limit 20,10
		Cursor cursor = db.rawQuery("select * from info order by _id desc limit ? offset ?", new String[] { String.valueOf(maxNumber), String.valueOf(startIndex) });
		List<ChatMsgEntity> list = new ArrayList<ChatMsgEntity>();
		String id;
		long time;
		String isShowTime;
		String userName;
		String userImg;
		String textMsg;
		String imgMsg;
		String voiceMsg;
		int msgType;
		String isMeMsg;
		while (cursor.moveToNext()) {
			id = String.valueOf(cursor.getInt(0));
			time = Long.parseLong(cursor.getString(1));
			isShowTime = cursor.getString(2);
			userName = cursor.getString(3);
			userImg = cursor.getString(4);
			textMsg = cursor.getString(5);
			imgMsg = cursor.getString(6);
			voiceMsg = cursor.getString(7);
			msgType = Integer.parseInt(cursor.getString(8));
			isMeMsg = cursor.getString(9);

			ChatMsgEntity entity = new ChatMsgEntity();
			entity.setId(id);
			entity.setTime(time);
			if ("0".equals(isShowTime)) {
				entity.setShowTime(false);
			} else {
				entity.setShowTime(true);
			}
			entity.setUserName(userName);
			entity.setUserImg(Integer.parseInt(userImg));
			entity.setTextMsg(textMsg);
			entity.setImgMsg(imgMsg);
			entity.setVoiceMsg(voiceMsg);
			entity.setMsgType(msgType);
			if ("0".equals(isMeMsg)) {
				entity.setMeMsg(false);
			} else {
				entity.setMeMsg(true);
			}
			list.add(0, entity);
		}
		cursor.close();
		db.close();
		return list;
	}
} public class ChatEmoji {

	/**
	 * 表情资源图片对应的ID
	 */
	private int id;
	/**
	 * 表情资源对应的文字描述
	 */
	private String description;
	/**
	 * 表情资源的文件名
	 */
	private String faceName;

	/** 表情资源图片对应的ID */
	public int getId() {
		return id;
	}

	/** 表情资源图片对应的ID */
	public void setId(int id) {
		this.id = id;
	}

	/** 表情资源对应的文字描述 */
	public String getDescription() {
		return description;
	}

	/** 表情资源对应的文字描述 */
	public void setDescription(String character) {
		this.description = character;
	}

	/** 表情资源的文件名 */
	public String getFaceName() {
		return faceName;
	}

	/** 表情资源的文件名 */
	public void setFaceName(String faceName) {
		this.faceName = faceName;
	}
} public class ChatMsgEntity {

	/**
	 * 文本消息
	 */
	public static final int MSGTYPE_TEXT = 1;
	/**
	 * 图片消息
	 */
	public static final int MSGTYPE_IMG = 2;
	/**
	 * 语音消息
	 */
	public static final int MSGTYPE_VOICE = 3;
	/**
	 * 分享消息
	 */
	public static final int MSGTYPE_SHARE = 4;
	/**
	 * 视频消息
	 */
	public static final int MSGTYPE_VIDEO = 5;

	/** 消息编号 **/
	private String id;

	/** 消息时间 **/
	private long time;

	/** 是否显示消息时间 **/
	private boolean isShowTime;

	/** 用户名称 **/
	private String userName;

	/** 用户头像 **/
	private int userImg;

	/** 文本消息内容 **/
	private String textMsg;

	/** 图片消息内容 **/
	private String imgMsg;

	/** 语音消息内容 **/
	private String voiceMsg;

	/** 消息类型(1：文本、2：图片、3：语音、4：分享、5：视频) **/
	private int msgType;

	/** 是否是我发送的消息 **/
	private boolean isMeMsg = true;

	public ChatMsgEntity() {
	}

	public ChatMsgEntity(String id, long time, boolean isShowTime, String userName, int userImg, String textMsg, String imgMsg, String voiceMsg, int msgType, boolean isMeMsg) {
		this.id = id;
		this.time = time;
		this.isShowTime = isShowTime;
		this.userName = userName;
		this.userImg = userImg;
		this.textMsg = textMsg;
		this.imgMsg = imgMsg;
		this.voiceMsg = voiceMsg;
		this.msgType = msgType;
		this.isMeMsg = isMeMsg;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public long getTime() {
		return time;
	}

	public void setTime(long time) {
		this.time = time;
	}

	public boolean isShowTime() {
		return isShowTime;
	}

	public void setShowTime(boolean isShowTime) {
		this.isShowTime = isShowTime;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public int getUserImg() {
		return userImg;
	}

	public void setUserImg(int userImg) {
		this.userImg = userImg;
	}

	public String getTextMsg() {
		return textMsg;
	}

	public void setTextMsg(String textMsg) {
		this.textMsg = textMsg;
	}

	public String getImgMsg() {
		return imgMsg;
	}

	public void setImgMsg(String imgMsg) {
		this.imgMsg = imgMsg;
	}

	public String getVoiceMsg() {
		return voiceMsg;
	}

	public void setVoiceMsg(String voiceMsg) {
		this.voiceMsg = voiceMsg;
	}

	public int getMsgType() {
		return msgType;
	}

	public void setMsgType(int msgType) {
		this.msgType = msgType;
	}

	public boolean isMeMsg() {
		return isMeMsg;
	}

	public void setMeMsg(boolean isMeMsg) {
		this.isMeMsg = isMeMsg;
	}
} public class User implements Parcelable {
	private String userPhote;
	private String userAccount;
	private String personalizedSignature;
	private String date;
	private Drawable userImage;

	public String getUserPhote() {
		return userPhote;
	}

	public void setUserPhote(String userPhote) {
		this.userPhote = userPhote;
	}

	public String getUserAccount() {
		return userAccount;
	}

	public void setUserAccount(String userAccount) {
		this.userAccount = userAccount;
	}

	public String getPersonalizedSignature() {
		return personalizedSignature;
	}

	public void setPersonalizedSignature(String personalizedSignature) {
		this.personalizedSignature = personalizedSignature;
	}

	public String getDate() {
		return date;
	}

	public void setDate(String date) {
		this.date = date;
	}

	public Drawable getUserImage() {
		return userImage;
	}

	public void setUserImage(Drawable userImage) {
		this.userImage = userImage;
	}

	@Override
	public int describeContents() {
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		dest.writeString(userPhote);
		dest.writeString(userAccount);
		dest.writeString(date);
		dest.writeString(personalizedSignature);
		dest.writeValue(userImage);
	}

	public static final Parcelable.Creator<User> CREATOR = new Parcelable.Creator<User>() {
		/**
		 * Return a new point from the data in the specified parcel.
		 */
		public User createFromParcel(Parcel in) {
			User u = new User();
			u.readFromParcel(in);
			return u;
		}

		/**
		 * Return an array of rectangles of the specified size.
		 */
		public User[] newArray(int size) {
			return new User[size];
		}
	};

	/**
	 * Set the point's coordinates from the data stored in the specified parcel.
	 * To write a point to a parcel, call writeToParcel().
	 * 
	 * @param in The parcel to read the point's coordinates from
	 */
	public void readFromParcel(Parcel in) {
		userPhote = in.readString();
		userAccount = in.readString();
		date = in.readString();
		personalizedSignature = in.readString();
		ClassLoader Drawable = ClassLoader.getSystemClassLoader();
		userImage = (android.graphics.drawable.Drawable) in.readValue(Drawable);
	}
} public class AppToast extends Toast {

	private static AppToast instance = null;
	private View layout;
	private TextView text;

	private AppToast() {
		super(GlobalParams.activity);
		init();
	}

	public static AppToast getToast() {
		if (instance == null) {
			instance = new AppToast();
		}
		return instance;
	}

	private void init() {
		LayoutInflater inflate = (LayoutInflater) GlobalParams.activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		layout = inflate.inflate(R.layout.cgt_transient_notification, null);
		text = (TextView) layout.findViewById(R.id.message);
		this.setView(layout);
	}

	public void show(String msg) {
		text.setText(msg);
		this.setDuration(Toast.LENGTH_SHORT);
		this.show();
	}

	public void show(int msg) {
		text.setText(msg);
		this.setDuration(Toast.LENGTH_SHORT);
		this.show();
	}

} public class DensityUtil {
  /** 
   * 根据手机的分辨率从 dip 的单位 转成为 px(像素) 
   */  
  public static int dip2px(Context context, float dpValue) {  
      final float scale = context.getResources().getDisplayMetrics().density;  
      return (int) (dpValue * scale + 0.5f);  
  }  

  /** 
   * 根据手机的分辨率从 px(像素) 的单位 转成为 dp 
   */  
  public static int px2dip(Context context, float pxValue) {  
      final float scale = context.getResources().getDisplayMetrics().density;  
      return (int) (pxValue / scale + 0.5f);  
  }  
}
 public class FaceConversionUtil {

	private static final String LOGTAG = LogUtil.makeLogTag(FaceConversionUtil.class);

	/** 每一页表情的个数 */
	private int pageSize = 20;

	private static FaceConversionUtil mFaceConversionUtil;

	/** 保存于内存中的表情HashMap(key:[可爱]; value:emoji_1) */
	private HashMap<String, String> mMap_emoji = new HashMap<String, String>();

	/** 保存于内存中的表情集合 */
	private List<ChatEmoji> mList_emoji = new ArrayList<ChatEmoji>();

	/** 表情分页的结果集合 */
	public List<List<ChatEmoji>> emojiLists = new ArrayList<List<ChatEmoji>>();

	private FaceConversionUtil() {

	}

	public static FaceConversionUtil getInstace() {
		if (mFaceConversionUtil == null) {
			mFaceConversionUtil = new FaceConversionUtil();
		}
		return mFaceConversionUtil;
	}

	/**
	 * 得到一个SpanableString对象，通过传入的字符串,并进行正则判断<br>
	 * 将特定字符转换成对应"表情"
	 * 
	 * @param context 上下文
	 * @param str 要被匹配的字符串
	 * @return
	 */
	public SpannableString getExpressionString(Context context, String str) {
		SpannableString spannableString = new SpannableString(str);
		// 正则表达式匹配字符串里是否含有表情，如： 我好[开心]啊
		String zhengze = "\\[[^\\]]+\\]";
		// 通过传入的正则表达式来生成一个pattern
		Pattern sinaPatten = Pattern.compile(zhengze, Pattern.CASE_INSENSITIVE);
		try {
			dealExpression(context, spannableString, sinaPatten, 0);
		} catch (Exception e) {
			L.e(LOGTAG, e.getMessage());
		}
		return spannableString;
	}

	/**
	 * 添加表情
	 * 
	 * @param context 上下文
	 * @param imgId
	 * @param spannableString
	 * @return
	 */
	public SpannableString addFace(Context context, int imgId, String spannableString) {
		if (TextUtils.isEmpty(spannableString)) {
			return null;
		}
		Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), imgId);
		bitmap = Bitmap.createScaledBitmap(bitmap, 48, 48, true);
		ImageSpan imageSpan = new ImageSpan(context, bitmap);
		SpannableString spannable = new SpannableString(spannableString);
		spannable.setSpan(imageSpan, 0, spannableString.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
		return spannable;
	}

	/**
	 * 对spanableString进行正则判断，如果符合要求，则以表情图片代替
	 * 
	 * @param context 上下文
	 * @param spannableString 一个SpannableString对象
	 * @param patten 一个Pattern对象(正则)
	 * @param start 起始位置
	 * @throws Exception
	 */
	private void dealExpression(Context context, SpannableString spannableString, Pattern patten, int start) throws Exception {
		Matcher matcher = patten.matcher(spannableString);
		while (matcher.find()) {//尝试查找与该模式匹配的输入序列的下一个子序列
			String key = matcher.group();//返回由以前匹配操作所匹配的输入子序列
			// 返回第一个字符的索引的文本匹配整个正则表达式,ture 则继续递归
			if (matcher.start() < start) {//返回以前匹配的初始索引
				continue;
			}
			String value = mMap_emoji.get(key);
			if (TextUtils.isEmpty(value)) {
				continue;
			}
			int resId = context.getResources().getIdentifier(value, "drawable", context.getPackageName());
			// 通过上面匹配得到的字符串来生成图片资源id
			// Field field=R.drawable.class.getDeclaredField(value);
			// int resId=Integer.parseInt(field.get(null).toString());
			if (resId != 0) {
				Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resId);
				bitmap = Bitmap.createScaledBitmap(bitmap, DensityUtil.dip2px(context, 48), DensityUtil.dip2px(context, 48), true);
				// 通过图片资源id来得到bitmap，用一个ImageSpan来包装
				ImageSpan imageSpan = new ImageSpan(bitmap);
				// 计算该图片名字的长度，也就是要替换的字符串的长度
				int end = matcher.start() + key.length();
				// 将该图片替换字符串中规定的位置中
				spannableString.setSpan(imageSpan, matcher.start(), end, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
				if (end < spannableString.length()) {
					// 如果整个字符串还未验证完，则继续。。
					dealExpression(context, spannableString, patten, end);
				}
				break;
			}
		}
	}

	/**
	 * 加载文本文件(表情清单文件)
	 * 
	 * @param context
	 */
	public void getFileText(Context context) {
		ParseData(FileUtils.getEmojiFile(context), context);
	}

	/**
	 * 解析字符
	 * 
	 * @param data
	 */
	private void ParseData(List<String> data, Context context) {
		if (data == null) {
			return;
		}
		ChatEmoji emoji;
		try {
			for (String str : data) {
				String[] text = str.split(",");
				String fileName = text[0].substring(0, text[0].lastIndexOf("."));
				mMap_emoji.put(text[1], fileName);
				int resID = context.getResources().getIdentifier(fileName, "drawable", context.getPackageName());

				if (resID != 0) {
					emoji = new ChatEmoji();
					emoji.setId(resID);
					emoji.setDescription(text[1]);//可爱
					emoji.setFaceName(fileName);//emoji_1
					mList_emoji.add(emoji);
				}
			}
			//每页20个，总共能生成多少页
			int pageCount = (int) Math.ceil(mList_emoji.size() / 20 + 0.1);

			for (int i = 0; i < pageCount; i++) {
				emojiLists.add(getData(i));
			}
		} catch (Exception e) {
			e.printStackTrace();
			L.e(LOGTAG, "ParseData--->" + e);
		}
	}

	/**
	 * 获取分页数据
	 * 
	 * @param page
	 * @return
	 */
	private List<ChatEmoji> getData(int page) {
		int startIndex = page * pageSize;//第page页的表情开始
		int endIndex = startIndex + pageSize;//第page页的表情结束

		//处理最后一页不足20个表情的问题，避免角标越界
		if (endIndex > mList_emoji.size()) {
			endIndex = mList_emoji.size();
		}
		// 不这么写，会在viewpager加载中报集合操作异常，我也不知道为什么
		List<ChatEmoji> list = new ArrayList<ChatEmoji>();
		list.addAll(mList_emoji.subList(startIndex, endIndex));
		if (list.size() < pageSize) {//一页不足20个表情的,给其添加空表情对象,以凑齐20个
			for (int i = list.size(); i < pageSize; i++) {
				ChatEmoji empty_ChatEmoji = new ChatEmoji();
				list.add(empty_ChatEmoji);
			}
		}
		if (list.size() == pageSize) {
			ChatEmoji object = new ChatEmoji();
			object.setId(R.drawable.cgt_selector_chat_emoji_del_bg);
			list.add(object);
		}
		return list;
	}
} public interface HandlerTypeUtils {
	/**
	 * 网络异常
	 */
	public static final int WX_HANDLER_HTTP_EXCEPTION = 10;
	/**
	 * 加载数据成功
	 */
	public static final int WX_HANDLER_TYPE_LOAD_DATA_SUCCESS = 11;
	/**
	 * 加载数据失败
	 */
	public static final int WX_HANDLER_TYPE_LOAD_DATA_FAIL = 12;
	/**
	 * 加载数据空
	 */
	public static final int WX_HANDLER_TYPE_LOAD_DATA_EMPTY = 13;
	/**
	 * 加载数据相同
	 */
	public static final int WX_HANDLER_TYPE_LOAD_DATA_SAME = 14;
	/**
	 * 刷新界面
	 */
	public static final int WX_HANDLER_TYPE_REFRESH = 15;
}
 public class L {
	private static final boolean flag = true;

	public static void i(String tag, String msg) {
		if (flag)
			Log.i(tag, msg);
	}

	public static void d(String tag, String msg) {
		if (flag)
			Log.d(tag, msg);
	}

	public static void e(String tag, String msg) {
		if (flag)
			Log.e(tag, msg);
	}

	public static void e(String tag, String msg, Throwable tr) {
		if (flag)
			Log.e(tag, msg, tr);
	}

	public static void v(String tag, String msg) {
		if (flag)
			Log.v(tag, msg);
	}

	public static void m(String tag, String msg) {
		if (flag)
			Log.e(tag, msg);
	}

	public static void w(String tag, String msg) {
		if (flag)
			Log.w(tag, msg);
	}
} public class LogUtil {

	@SuppressWarnings("unchecked")
	public static String makeLogTag(Class cls) {
		return "Weixin_" + cls.getSimpleName();
	}

}
 public class ChatMsgAdapter extends BaseAdapter {

	private Context mContext;
	private LayoutInflater mInflater;
	private List<ChatMsgEntity> mList;

	public ChatMsgAdapter(Context context, List<ChatMsgEntity> list) {
		this.mContext = context;
		this.mInflater = LayoutInflater.from(context);
		this.mList = list;
	}

	@Override
	public int getCount() {
		if (mList != null) {
			return mList.size();
		}
		return 0;
	}

	@Override
	public Object getItem(int position) {
		if (mList != null) {
			return mList.get(position);
		}
		return null;
	}

	@Override
	public long getItemId(int position) {
		if (mList != null) {
			return position;
		}
		return 0;
	}

	@Override
	public int getItemViewType(int position) {
		ChatMsgEntity entity = mList.get(position);
		if (entity.isMeMsg()) {
			return 0;
		} else {
			return 1;
		}
	}

	@Override
	public int getViewTypeCount() {
		return 2;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ChatMsgEntity entity = mList.get(position);

		ViewHolder viewHolder = null;
		if (convertView == null) {
			if (entity.isMeMsg()) {
				convertView = mInflater.inflate(R.layout.cgt_layout_chat_msg_text_right, null);
			} else {
				convertView = mInflater.inflate(R.layout.cgt_layout_chat_msg_text_left, null);
			}
			viewHolder = getViewHolder(convertView);
			convertView.setTag(viewHolder);
		} else {
			viewHolder = (ViewHolder) convertView.getTag();
		}
		setData(viewHolder, entity);
		return convertView;
	}

	private void setData(ViewHolder viewHolder, ChatMsgEntity entity) {
		switch (entity.getMsgType()) {
		case ChatMsgEntity.MSGTYPE_TEXT:
			viewHolder.mTv_time.setText(AppUtil.formatTime(entity.getTime()));
			viewHolder.mIv_userImg.setImageResource(entity.getUserImg());
			SpannableString spannableString = FaceConversionUtil.getInstace().getExpressionString(mContext, entity.getTextMsg());
			viewHolder.mTv_msg_text.setText(spannableString);

			viewHolder.mTv_msg_text.setVisibility(View.VISIBLE);
			if (entity.isShowTime()) {
				viewHolder.mTv_time.setVisibility(View.VISIBLE);
			} else {
				viewHolder.mTv_time.setVisibility(View.GONE);
			}
			break;
		case ChatMsgEntity.MSGTYPE_IMG:

			break;
		case ChatMsgEntity.MSGTYPE_VOICE:

			break;
		case ChatMsgEntity.MSGTYPE_SHARE:

			break;
		case ChatMsgEntity.MSGTYPE_VIDEO:

			break;

		default:
			break;
		}
	}

	private ViewHolder getViewHolder(View v) {
		ViewHolder viewHolder = new ViewHolder();
		viewHolder.mTv_time = (TextView) v.findViewById(R.id.cgt_tv_chat_msg_time);
		viewHolder.mIv_userImg = (ImageView) v.findViewById(R.id.cgt_iv_chat_userImg);
		viewHolder.mTv_msg_text = (TextView) v.findViewById(R.id.cgt_tv_chat_msg_text);
		return viewHolder;
	}

	class ViewHolder {
		/** 消息发送时间 **/
		TextView mTv_time;
		/** 头像 **/
		ImageView mIv_userImg;
		/** 文本消息 **/
		TextView mTv_msg_text;
	}

} public class EmojiAdapter extends BaseAdapter {

	/**
	 * 上下文
	 */
	private Context mContext;
	/**
	 * 表情集合
	 */
	private List<ChatEmoji> mList_chatEmoji;

	public EmojiAdapter(Context context, List<ChatEmoji> list) {
		this.mContext = context;
		this.mList_chatEmoji = list;
	}

	@Override
	public int getCount() {
		if (mList_chatEmoji == null) {
			return 0;
		}
		return mList_chatEmoji.size();
	}

	@Override
	public Object getItem(int position) {
		return mList_chatEmoji.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		ChatEmoji emoji = mList_chatEmoji.get(position);
		ViewHolder viewHolder = null;
		if (convertView == null) {
			viewHolder = new ViewHolder();
			convertView = View.inflate(mContext, R.layout.cgt_layout_chat_emoji_item, null);
			viewHolder.mIv_emoji = (ImageView) convertView.findViewById(R.id.cgt_iv_chat_item_emoji);
			convertView.setTag(viewHolder);
		} else {
			viewHolder = (ViewHolder) convertView.getTag();
		}

		if (emoji.getId() == R.drawable.cgt_selector_chat_emoji_del_bg) {
//			convertView.setBackgroundDrawable(null);
			viewHolder.mIv_emoji.setImageResource(emoji.getId());
		} else if (TextUtils.isEmpty(emoji.getDescription())) {
			convertView.setBackgroundDrawable(null);
			viewHolder.mIv_emoji.setImageDrawable(null);
		} else {
			viewHolder.mIv_emoji.setTag(emoji);
			viewHolder.mIv_emoji.setImageResource(emoji.getId());
		}

		return convertView;
	}

	class ViewHolder {
		ImageView mIv_emoji;
	}
} public class XmppManager {

	private static final String LOGTAG = LogUtil.makeLogTag(XmppManager.class);

	private Context context;

	/** 加载配置文件 **/
	private Properties props;

	private String version = "0.0.1";

	private String apiKey;

	private String xmppHost;

	private String xmppPort;

	/** 回调Activity的包名 **/
	private String callbackActivityPackageName;

	/** 回调Activity的全类名 **/
	private String callbackActivityClassName;

	private XMPPConnection connection;

	private static XmppManager xmppManager;

	/** 聊天监听器 **/
	private TaxiChatManagerListener chatManagerListener;

	public static XmppManager getInstance() {
		if (xmppManager == null) {
			xmppManager = new XmppManager(GlobalParams.activity);
			return xmppManager;
		}
		return xmppManager;
	}

	private XmppManager(Context context) {
		this.context = context;
		init(context);
	}

	private void init(Context context) {
		if (context instanceof Activity) {
			L.i(LOGTAG, "Callback Activity...");
			Activity callbackActivity = (Activity) context;
			callbackActivityPackageName = callbackActivity.getPackageName();
			callbackActivityClassName = callbackActivity.getClass().getName();
		}

		props = loadProperties();
		apiKey = props.getProperty("apiKey", "");
		xmppHost = props.getProperty("xmppHost", "127.0.0.1");
		xmppPort = props.getProperty("xmppPort", "5222");
		L.i(LOGTAG, "apiKey=" + apiKey);
		L.i(LOGTAG, "xmppHost=" + xmppHost);
		L.i(LOGTAG, "xmppPort=" + xmppPort);

		SpUtil sp = new SpUtil(context);
		sp.saveString(Constants.API_KEY, apiKey);
		sp.saveString(Constants.VERSION, version);
		sp.saveString(Constants.XMPP_HOST, xmppHost);
		sp.saveInt(Constants.XMPP_PORT, Integer.parseInt(xmppPort));
		sp.saveString(Constants.CALLBACK_ACTIVITY_PACKAGE_NAME, callbackActivityPackageName);
		sp.saveString(Constants.CALLBACK_ACTIVITY_CLASS_NAME, callbackActivityClassName);

		connectServer();
	}

	/**
	 * 加载Properties配置文件
	 * 
	 * @return
	 */
	private Properties loadProperties() {
		Properties props = new Properties();
		try {
			int id = context.getResources().getIdentifier("weixin", "raw", context.getPackageName());
			props.load(context.getResources().openRawResource(id));
		} catch (Exception e) {
			L.e(LOGTAG, "Could not find the properties file.", e);
		}
		return props;
	}

	/**
	 * 得到xmpp连接
	 * 
	 * @return
	 */
	public XMPPConnection getConnection() {
		return connection;
	}

	/**
	 * 设置连接
	 * 
	 * @param connection 一个xmpp连接
	 */
	public void setConnection(XMPPConnection connection) {
		this.connection = connection;
	}

	/**
	 * xmpp连接是否建立并连接成功
	 * 
	 * @return
	 */
	private boolean isConnected() {
		return connection != null && connection.isConnected();
	}

	/**
	 * 与服务器建立连接
	 * 
	 * @return
	 */
	public boolean connectServer() {
		ConnectionConfiguration connConfig = new ConnectionConfiguration(xmppHost, Integer.parseInt(xmppPort));
		//设置安全模式
		connConfig.setSecurityMode(SecurityMode.required);
		//设置SASL认证是否启用
		connConfig.setSASLAuthenticationEnabled(false);
		//设置数据压缩是否启用
		connConfig.setCompressionEnabled(false);
		//是否启用调试模式
		connConfig.setDebuggerEnabled(true);

		/** 创建connection连接 */
		XMPPConnection connection = new XMPPConnection(connConfig);
		this.setConnection(connection);

		try {
			// 连接到服务器
			connection.connect();
			L.i(LOGTAG, "XMPP connected successfully");
			return true;
		} catch (XMPPException e) {
			L.e(LOGTAG, "XMPP connection failed", e);
		}
		return false;
	}

	/**
	 * 注册
	 * 
	 * @param account 注册帐号
	 * @param password 注册密码
	 * @return 0、 服务器没有返回结果<br>
	 *         1、注册成功 <br>
	 *         2、这个帐号已经存在 <br>
	 *         3、注册失败
	 */
	public String regist(String account, String password) {
		if (!isConnected()) {
			return "0";
		}
		Registration reg = new Registration();
		reg.setType(IQ.Type.SET);
		reg.setTo(getConnection().getServiceName());
		reg.setUsername(account);
		reg.setPassword(password);
		reg.addAttribute("android", "geolo_createUser_android");

		//数据包过滤器
		PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()), new PacketTypeFilter(IQ.class));
		PacketCollector collector = getConnection().createPacketCollector(filter);
		getConnection().sendPacket(reg);

		IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
		//停止请求result(是否成功的结果)
		collector.cancel();
		if (result == null) {
			L.e(LOGTAG, "No response from server.");
			return "0";
		} else if (result.getType() == IQ.Type.RESULT) {
			return "1";
		} else {
			if (result.getError().toString().equalsIgnoreCase("conflict(409)")) {
				L.e(LOGTAG, "IQ.Type.ERROR: " + result.getError().toString());
				return "2";
			} else {
				L.e(LOGTAG, "IQ.Type.ERROR: " + result.getError().toString());
				return "3";
			}
		}
	}

	/**
	 * 获取一个聊天监听器
	 * 
	 * @return
	 */
	public TaxiChatManagerListener getChatManagerListener() {
		return this.chatManagerListener;
	}

	/**
	 * 登陆
	 * 
	 * @param account 账户名
	 * @param password 密码
	 * @return
	 */
	public boolean login(String account, String password) {
		try {
			//登陆
			getConnection().login(account, password);

			/** 开启读写线程，并加入到管理类中 */
			//ClientSendThread cst = new ClientSendThread(connection);
			//cst.start();
			//ManageClientThread.addClientSendThread(account,cst);

			// 添加监听，最好是放在登录方法中，在关闭连接方法中，移除监听，原因是为了避免重复添加监听，接受重复消息
			// 退出程序应该关闭连接，移除监听，该监听可以接受所有好友的消息，很方便吧~
			chatManagerListener = new TaxiChatManagerListener();
			getConnection().getChatManager().addChatListener(chatManagerListener);

			return true;
		} catch (XMPPException e) {
			L.e(LOGTAG, "XMPP connection failed", e);
		}
		return false;
	}

	/**
	 * 登出
	 * 
	 * @return
	 */
	public boolean logout() {
		// 添加监听，最好是放在登录方法中，在关闭连接方法中，移除监听，原因是为了避免重复添加监听，接受重复消息
		// 退出程序应该关闭连接，移除监听，该监听可以接受所有好友的消息，很方便吧~
		getConnection().getChatManager().removeChatListener(chatManagerListener);

		//退出登录
		getConnection().disconnect();

		if (isConnected()) {
			return true;
		}
		return false;
	}

	/**
	 * 修改密码
	 * 
	 * @param password
	 * @return
	 */
	public boolean changePassword(String password) {
		try {
			getConnection().getAccountManager().changePassword(password);
			return true;
		} catch (XMPPException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 更改用户状态
	 * 
	 * @param code--><br>
	 *            0、在线<br>
	 *            1、Q我吧<br>
	 *            2、忙碌<br>
	 *            3、离开<br>
	 *            4、隐身<br>
	 *            5、离线
	 */
	public void setPresence(int code) {
		if (!isConnected()) {
			return;
		}
		Presence presence;
		switch (code) {
		case 0:
			presence = new Presence(Presence.Type.available);
			getConnection().sendPacket(presence);
			L.v(LOGTAG, "设置在线");
			break;
		case 1:
			presence = new Presence(Presence.Type.available);
			presence.setMode(Presence.Mode.chat);
			getConnection().sendPacket(presence);
			L.v(LOGTAG, "设置Q我吧");
			L.d(LOGTAG, "Q我吧--->" + presence.toXML());
			break;
		case 2:
			presence = new Presence(Presence.Type.available);
			presence.setMode(Presence.Mode.dnd);
			getConnection().sendPacket(presence);
			L.v(LOGTAG, "设置忙碌");
			L.d(LOGTAG, "忙碌--->" + presence.toXML());
			break;
		case 3:
			presence = new Presence(Presence.Type.available);
			presence.setMode(Presence.Mode.away);
			getConnection().sendPacket(presence);
			L.v(LOGTAG, "设置离开");
			L.d(LOGTAG, "离开--->" + presence.toXML());
			break;
		case 4:
			Roster roster = getConnection().getRoster();
			Collection<RosterEntry> entries = roster.getEntries();
			for (RosterEntry entry : entries) {
				presence = new Presence(Presence.Type.unavailable);
				presence.setPacketID(Packet.ID_NOT_AVAILABLE);
				presence.setFrom(getConnection().getUser());
				presence.setTo(entry.getUser());
				getConnection().sendPacket(presence);
				L.d(LOGTAG, entry.getUser() + "--->" + presence.toXML());
			}
			//向同一用户的其他客户端发送隐身状态
			presence = new Presence(Presence.Type.unavailable);
			presence.setPacketID(Packet.ID_NOT_AVAILABLE);
			presence.setFrom(getConnection().getUser());
			presence.setTo(StringUtils.parseBareAddress(getConnection().getUser()));
			getConnection().sendPacket(presence);
			L.v(LOGTAG, "设置隐身");
			break;
		case 5:
			presence = new Presence(Presence.Type.unavailable);
			getConnection().sendPacket(presence);
			L.v(LOGTAG, "设置离线");
			break;
		default:
			break;
		}
	}

	/**
	 * 删除当前账户
	 * 
	 * @return
	 */
	public boolean deleteAccount() {
		try {
			getConnection().getAccountManager().deleteAccount();
			return true;
		} catch (XMPPException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 获得所有组
	 * 
	 * @param roster
	 * @return 所有组集合
	 */
	public List<RosterGroup> getGroups(Roster roster) {
		List<RosterGroup> groupList = new ArrayList<RosterGroup>();
		Collection<RosterGroup> rosterGroups = roster.getGroups();
		Iterator<RosterGroup> i = rosterGroups.iterator();
		while (i.hasNext()) {
			groupList.add(i.next());
		}
		return groupList;
	}

	/**
	 * 添加分组
	 * 
	 * @param roster
	 * @param groupName 分组名
	 * @return
	 */
	public boolean addGroup(Roster roster, String groupName) {
		try {
			roster.createGroup(groupName);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 获得某个组里面的所有好友
	 * 
	 * @param roster
	 * @param groupName 组名
	 * @return
	 */
	public List<RosterEntry> getEntriesByGroup(Roster roster, String groupName) {
		List<RosterEntry> entriesList = new ArrayList<RosterEntry>();
		RosterGroup rosterGroup = roster.getGroup(groupName);
		Collection<RosterEntry> rosterEntries = rosterGroup.getEntries();
		Iterator<RosterEntry> i = rosterEntries.iterator();
		while (i.hasNext()) {
			entriesList.add(i.next());
		}
		return entriesList;
	}

	/**
	 * 获取所有好友信息
	 * 
	 * @param roster
	 * @return
	 */
	public List<RosterEntry> getAllEntries(Roster roster) {
		List<RosterEntry> entriesList = new ArrayList<RosterEntry>();
		Collection<RosterEntry> rosterEntries = roster.getEntries();
		Iterator<RosterEntry> i = rosterEntries.iterator();
		while (i.hasNext()) {
			entriesList.add(i.next());
		}
		return entriesList;
	}

	/**
	 * 获取所有好友信息
	 * 
	 * @param roster
	 * @return
	 */
	public List<User> getAllUser(Roster roster) {
		List<User> mList_user = new ArrayList<User>();
		Collection<RosterEntry> entries = roster.getEntries();
		Iterator<RosterEntry> iterator = entries.iterator();
		while (iterator.hasNext()) {
			RosterEntry entry = iterator.next();
			User user = new User();
			user.setUserAccount(entry.getName());
			user.setUserPhote(String.valueOf(R.drawable.user_picture));
//			user.setUserImage(getUserImage(entry.getName()));
			mList_user.add(user);
			L.i(LOGTAG, "------获取好友-getAllUser----------------------");
			L.i(LOGTAG, "getAllUser-getName-->" + entry.getName());
			L.i(LOGTAG, "getAllUser-getUser-->" + entry.getUser());
			L.i(LOGTAG, "getAllUser-getStatus-->" + entry.getStatus());
		}
		return mList_user;
	}

	/**
	 * 获取用户VCard信息
	 * 
	 * @param user
	 * @return
	 * @throws XMPPException
	 */
	public VCard getUserVCard(String user) throws XMPPException {
		VCard vCard = new VCard();
		vCard.load(getConnection(), user);
		return vCard;
	}

	/**
	 * 获取用户头像信息
	 * 
	 * @param user
	 * @return
	 */
	public Drawable getUserImage(String user) {
		ByteArrayInputStream bais = null;
		try {
			VCard vCard = new VCard();
			//加入这句，解决没有No VCard
			ProviderManager.getInstance().addIQProvider("vCard", "vcard-temp", new org.jivesoftware.smackx.provider.VCardProvider());
			vCard.load(getConnection(), user + "@" + getConnection().getServiceName());
			if (vCard == null || vCard.getAvatar() == null) {
				return null;
			}
			bais = new ByteArrayInputStream(vCard.getAvatar());
		} catch (Exception e) {
			e.printStackTrace();
		}
		if (bais == null) {
			return null;
		}
		return FormatTools.getInstance().InputStream2Drawable(bais);
	}

	/**
	 * 添加好友--无分组
	 * 
	 * @param roster
	 * @param userName
	 * @param name
	 * @return
	 */
	public boolean addUser(Roster roster, String userName, String name) {
		try {
			roster.createEntry(userName, name, null);
			return true;
		} catch (XMPPException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 添加好友--有分组
	 * 
	 * @param roster
	 * @param userName
	 * @param name
	 * @param groupName
	 * @return
	 */
	public boolean addUser(Roster roster, String userName, String name, String groupName) {
		try {
			roster.createEntry(userName, name, new String[] { groupName });
			return true;
		} catch (XMPPException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 删除好友
	 * 
	 * @param roster
	 * @param userName
	 * @return
	 */
	public boolean removeUser(Roster roster, String userName) {
		try {
			if (userName.contains("@")) {
				userName = userName.split("@")[0];
			}
			RosterEntry entry = roster.getEntry(userName);
			L.i(LOGTAG, "删除好友--->" + userName);
			L.d(LOGTAG, "User." + (roster.getEntry(userName) == null));
			roster.removeEntry(entry);
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 查询用户
	 * 
	 * @param serverDomain
	 * @param userName
	 * @return
	 * @throws XMPPException
	 */
	public List<User> searchUsers(String serverDomain, String userName) throws XMPPException {
		List<User> results = new ArrayList<User>();
		L.i(LOGTAG, "查询开始--->Host=" + getConnection().getHost() + "  ServiceName=" + getConnection().getServiceName());

		UserSearchManager usm = new UserSearchManager(getConnection());
		Form searchForm = usm.getSearchForm(serverDomain);
		Form answerForm = searchForm.createAnswerForm();
		answerForm.setAnswer("userAccount", true);
		answerForm.setAnswer("userPhote", userName);
		ReportedData data = usm.getSearchResults(answerForm, serverDomain);

		Iterator<Row> i = data.getRows();
		Row row = null;
		User user = null;
		while (i.hasNext()) {
			user = new User();
			row = i.next();
			user.setUserAccount(row.getValues("userAccount").next().toString());
			user.setUserPhote(row.getValues("userPhote").next().toString());
			results.add(user);
			//若存在，则有返回，userName一定非空，其他两个若是有设，一定非空
		}
		return results;
	}

	/**
	 * 修改用户头像
	 * 
	 * @param f
	 * @throws XMPPException
	 * @throws IOException
	 */
	public void changeUserImage(File f) throws XMPPException, IOException {
		VCard vCard = new VCard();
		vCard.load(getConnection());
		byte[] bytes = getFileBytes(f);

		String encodeImage = StringUtils.encodeBase64(bytes);
		vCard.setAvatar(bytes, encodeImage);
		vCard.setEncodedImage(encodeImage);
		vCard.setField("PHOTO", "<TYPE>image/jpg</TYPE><BINVAL>" + encodeImage + "</BINVAL>", true);

		ByteArrayInputStream bais = new ByteArrayInputStream(vCard.getAvatar());
		FormatTools.getInstance().InputStream2Bitmap(bais);
		vCard.save(getConnection());
	}

	/**
	 * 获取一个文件的字符流
	 * 
	 * @param file
	 * @return
	 * @throws IOException
	 */
	private byte[] getFileBytes(File file) throws IOException {
		BufferedInputStream bis = null;
		try {
			bis = new BufferedInputStream(new FileInputStream(file));
			int bytes = (int) file.length();
			byte[] buffer = new byte[bytes];
			int readBytes = bis.read(buffer);
			if (readBytes != buffer.length) {
				throw new IOException("Entire file not read");
			}
			return buffer;
		} finally {
			if (bis != null) {
				bis.close();
			}
		}
	}

	/**
	 * 创建房间
	 * 
	 * @param roomName 房间名称
	 */
	public void createRoom(String roomName) {
		if (!isConnected()) {
			return;
		}
		try {
			// 创建一个MultiUserChat  
			MultiUserChat muc = new MultiUserChat(getConnection(), roomName + "@conference." + getConnection().getServiceName());
			// 创建聊天室  
			muc.create(roomName); // roomName房间的名字  
			// 获得聊天室的配置表单  
			Form form = muc.getConfigurationForm();
			// 根据原始表单创建一个要提交的新表单。  
			Form submitForm = form.createAnswerForm();
			// 向要提交的表单添加默认答复  
			for (Iterator<FormField> fields = form.getFields(); fields.hasNext();) {
				FormField field = (FormField) fields.next();
				if (!FormField.TYPE_HIDDEN.equals(field.getType()) && field.getVariable() != null) {
					// 设置默认值作为答复  
					submitForm.setDefaultAnswer(field.getVariable());
				}
			}
			// 设置聊天室的新拥有者  
			List<String> owners = new ArrayList<String>();
			owners.add(getConnection().getUser());// 用户JID  
			submitForm.setAnswer("muc#roomconfig_roomowners", owners);
			// 设置聊天室是持久聊天室，即将要被保存下来  
			submitForm.setAnswer("muc#roomconfig_persistentroom", false);
			// 房间仅对成员开放  
			submitForm.setAnswer("muc#roomconfig_membersonly", false);
			// 允许占有者邀请其他人  
			submitForm.setAnswer("muc#roomconfig_allowinvites", true);
			// 进入是否需要密码  
			//submitForm.setAnswer("muc#roomconfig_passwordprotectedroom", true);  
			// 设置进入密码  
			//submitForm.setAnswer("muc#roomconfig_roomsecret", "password");  
			// 能够发现占有者真实 JID 的角色  
			// submitForm.setAnswer("muc#roomconfig_whois", "anyone");  
			// 登录房间对话  
			submitForm.setAnswer("muc#roomconfig_enablelogging", true);
			// 仅允许注册的昵称登录  
			submitForm.setAnswer("x-muc#roomconfig_reservednick", true);
			// 允许使用者修改昵称  
			submitForm.setAnswer("x-muc#roomconfig_canchangenick", false);
			// 允许用户注册房间  
			submitForm.setAnswer("x-muc#roomconfig_registration", false);
			// 发送已完成的表单（有默认值）到服务器来配置聊天室  
			submitForm.setAnswer("muc#roomconfig_passwordprotectedroom", true);
			// 发送已完成的表单（有默认值）到服务器来配置聊天室  
			muc.sendConfigurationForm(submitForm);
		} catch (XMPPException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 加入会议室
	 * 
	 * @param user 昵称
	 * @param password 会议室密码
	 * @param roomsName 会议室名
	 */
	public MultiUserChat joinMultiUserChat(String user, String password, String roomsName) {
		try {
			// 使用XMPPConnection创建一个MultiUserChat窗口  
			MultiUserChat muc = new MultiUserChat(getConnection(), roomsName + "@conference." + getConnection().getServiceName());
			// 聊天室服务将会决定要接受的历史记录数量  
			DiscussionHistory history = new DiscussionHistory();
			history.setMaxStanzas(0);
			//history.setSince(new Date());  
			// 用户加入聊天室  
			muc.join(user, password, history, SmackConfiguration.getPacketReplyTimeout());
			L.i(LOGTAG, "会议室加入成功........");
			return muc;
		} catch (XMPPException e) {
			e.printStackTrace();
			L.i(LOGTAG, "会议室加入失败........");
			return null;
		}
	}

	/**
	 * 查询会议室成员名字
	 * 
	 * @param muc
	 */
	public List<String> findMulitUser(MultiUserChat muc) {
		List<String> listUser = new ArrayList<String>();
		Iterator<String> it = muc.getOccupants();
		//遍历出聊天室人员名称  
		while (it.hasNext()) {
			// 聊天室成员名字  
			String name = StringUtils.parseResource(it.next());
			listUser.add(name);
		}
		return listUser;
	}

	/**
	 * 获取服务器上所有会议室
	 * 
	 * @return
	 * @throws XMPPException
	 */
	public List<FriendRooms> getConferenceRoom() throws XMPPException {
		List<FriendRooms> list = new ArrayList<FriendRooms>();
		new ServiceDiscoveryManager(getConnection());
		if (!MultiUserChat.getHostedRooms(getConnection(), getConnection().getServiceName()).isEmpty()) {

			for (HostedRoom k : MultiUserChat.getHostedRooms(getConnection(), getConnection().getServiceName())) {

				for (HostedRoom j : MultiUserChat.getHostedRooms(getConnection(), k.getJid())) {
					RoomInfo info2 = MultiUserChat.getRoomInfo(getConnection(), j.getJid());
					if (j.getJid().indexOf("@") > 0) {

						FriendRooms friendrooms = new FriendRooms();
						friendrooms.setName(j.getName());//聊天室的名称  
						friendrooms.setJid(j.getJid());//聊天室JID  
						friendrooms.setOccupants(info2.getOccupantsCount());//聊天室中占有者数量  
						friendrooms.setDescription(info2.getDescription());//聊天室的描述  
						friendrooms.setSubject(info2.getSubject());//聊天室的主题  
						list.add(friendrooms);
					}
				}
			}
		}
		return list;
	}

	//	五、监听会议室的消息
	//	添加会议室消息监听 ：
	//multiChat.addMessageListener(new multiListener());
	/**
	 * 会议室信息监听事件
	 * 
	 * @author Administrator
	 * 
	 */
	public class multiListener implements PacketListener {
		@Override
		public void processPacket(Packet packet) {
			Message message = (Message) packet;
			// 接收来自聊天室的聊天信息  
			String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
			MucHistory mh = new MucHistory();
			//			mh.setUserAccount(account);
			String from = StringUtils.parseResource(message.getFrom());
			String fromRoomName = StringUtils.parseName(message.getFrom());
			mh.setMhRoomName(fromRoomName);
			mh.setFriendAccount(from);
			mh.setMhInfo(message.getBody());
			mh.setMhTime(time);
			mh.setMhType("left");
		}
	}

	//六、发送会议室消息
	//    multiChat.sendMessage(str);//multiChat 为聊天室对象

	//	七、监听会议室状态（成员的进入、离开等）
	//	添加监听事件：
	//    multiChat.addParticipantStatusListener(new ParticipantStatus());

	/**
	 * 会议室状态监听事件
	 * 
	 * @author Administrator
	 * 
	 */
	class ParticipantStatus implements ParticipantStatusListener {

		@Override
		public void adminGranted(String arg0) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void adminRevoked(String arg0) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void banned(String arg0, String arg1, String arg2) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void joined(String participant) {
			System.out.println(StringUtils.parseResource(participant) + " has joined the room.");
		}

		@Override
		public void kicked(String arg0, String arg1, String arg2) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void left(String participant) {
			// TODO Auto-generated method stub  
			System.out.println(StringUtils.parseResource(participant) + " has left the room.");

		}

		@Override
		public void membershipGranted(String arg0) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void membershipRevoked(String arg0) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void moderatorGranted(String arg0) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void moderatorRevoked(String arg0) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void nicknameChanged(String participant, String newNickname) {
			System.out.println(StringUtils.parseResource(participant) + " is now known as " + newNickname + ".");
		}

		@Override
		public void ownershipGranted(String arg0) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void ownershipRevoked(String arg0) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void voiceGranted(String arg0) {
			// TODO Auto-generated method stub  

		}

		@Override
		public void voiceRevoked(String arg0) {
			// TODO Auto-generated method stub  

		}
	}

	//	一、单人聊天
	//	1）发送消息：
	//	首先要获取一个聊天窗口，getConnection()为获取连接connection的方法，调用getFriendChat()获取

	private Map<String, Chat> chatManage = new HashMap<String, Chat>();// 聊天窗口管理map集合

	/**
	 * 获取或创建聊天窗口
	 * 
	 * @param friend 好友名
	 * @param listenter 聊天監聽器
	 * @return
	 */
	public Chat getFriendChat(String friend, MessageListener listenter) {
		if (getConnection() == null)
			return null;
		/** 判断是否创建聊天窗口 */
		for (String fristr : chatManage.keySet()) {
			if (fristr.equals(friend)) {
				// 存在聊天窗口，则返回对应聊天窗口
				return chatManage.get(fristr);
			}
		}
		/** 创建聊天窗口 */
		Chat chat = getConnection().getChatManager().createChat(friend + "@" + getConnection().getServiceName(), listenter);
		/** 添加聊天窗口到chatManage */
		chatManage.put(friend, chat);
		return chat;
	}

	//	friend为好友名，不是JID；listener 监听器可以传null，利用聊天窗口对象调用sendMessage发送消息
	//	这里sendMessage我传的是一个JSON字符串，以便更灵活的控制，发送消息完成~
	//	Chat chat = getFriendChat(friend,null);
	//	try {
	//	 	String msgjson = "{\"messageType\":\""+messageType+"\",\"chanId\":\""+chanId+"\",\"chanName\":\""+chanName+"\"}";
	//		chat.sendMessage(msgjson);
	//	} catch (XMPPException e) {
	//		e.printStackTrace();
	//	}

	//	添加监听，最好是放在登录方法中，在关闭连接方法中，移除监听，原因是为了避免重复添加监听，接受重复消息
	//	退出程序应该关闭连接，移除监听，该监听可以接受所有好友的消息，很方便吧~
	//	TaxiChatManagerListener chatManagerListener = new TaxiChatManagerListener();  
	//	getConnection().getChatManager().addChatListener(chatManagerListener); 

	//	connection.getChatManager().removeChatListener(chatManagerListener);

	//	二、多人聊天（会议室）
	//	1）、发送消息
	//	首先要获取会议室对象（MultiUserChat），有两种方法获取
	//	两个方法前面都有讲到，这里再回顾一下
	//	1、创建会议室
	/**
	 * 创建房间
	 * 
	 * @param user
	 * @param roomName 房间名称
	 * @param password
	 * @return
	 */
	public MultiUserChat createRoom(String user, String roomName, String password) {
		if (getConnection() == null)
			return null;

		MultiUserChat muc = null;
		try {
			// 创建一个MultiUserChat
			muc = new MultiUserChat(getConnection(), roomName + "@conference." + getConnection().getServiceName());
			// 创建聊天室
			muc.create(roomName);
			// 获得聊天室的配置表单
			Form form = muc.getConfigurationForm();
			// 根据原始表单创建一个要提交的新表单。
			Form submitForm = form.createAnswerForm();
			// 向要提交的表单添加默认答复
			for (Iterator<FormField> fields = form.getFields(); fields.hasNext();) {
				FormField field = (FormField) fields.next();
				if (!FormField.TYPE_HIDDEN.equals(field.getType()) && field.getVariable() != null) {
					// 设置默认值作为答复
					submitForm.setDefaultAnswer(field.getVariable());
				}
			}
			// 设置聊天室的新拥有者
			List<String> owners = new ArrayList<String>();
			owners.add(getConnection().getUser());// 用户JID
			submitForm.setAnswer("muc#roomconfig_roomowners", owners);
			// 设置聊天室是持久聊天室，即将要被保存下来
			submitForm.setAnswer("muc#roomconfig_persistentroom", true);
			// 房间仅对成员开放
			submitForm.setAnswer("muc#roomconfig_membersonly", false);
			// 允许占有者邀请其他人
			submitForm.setAnswer("muc#roomconfig_allowinvites", true);
			if (!password.equals("")) {
				// 进入是否需要密码
				submitForm.setAnswer("muc#roomconfig_passwordprotectedroom", true);
				// 设置进入密码
				submitForm.setAnswer("muc#roomconfig_roomsecret", password);
			}
			// 能够发现占有者真实 JID 的角色
			// submitForm.setAnswer("muc#roomconfig_whois", "anyone");
			// 登录房间对话
			submitForm.setAnswer("muc#roomconfig_enablelogging", true);
			// 仅允许注册的昵称登录
			submitForm.setAnswer("x-muc#roomconfig_reservednick", true);
			// 允许使用者修改昵称
			submitForm.setAnswer("x-muc#roomconfig_canchangenick", false);
			// 允许用户注册房间
			submitForm.setAnswer("x-muc#roomconfig_registration", false);
			// 发送已完成的表单（有默认值）到服务器来配置聊天室
			muc.sendConfigurationForm(submitForm);
		} catch (XMPPException e) {
			e.printStackTrace();
			return null;
		}
		return muc;
	}

	//	/**
	//	 * 加入会议室
	//	 * 
	//	 * @param user 昵称
	//	 * @param password 会议室密码
	//	 * @param roomsName 会议室名
	//	 */
	//	public MultiUserChat joinMultiUserChat(String user, String roomsName, String password) {
	//		if (getConnection() == null)
	//			return null;
	//		try {
	//			// 使用XMPPConnection创建一个MultiUserChat窗口
	//			MultiUserChat muc = new MultiUserChat(getConnection(), roomsName + "@conference." + getConnection().getServiceName());
	//			// 聊天室服务将会决定要接受的历史记录数量
	//			DiscussionHistory history = new DiscussionHistory();
	//			history.setMaxChars(0);
	//			// history.setSince(new Date());
	//			// 用户加入聊天室
	//			muc.join(user, password, history, SmackConfiguration.getPacketReplyTimeout());
	//			L.i("MultiUserChat", "会议室【" + roomsName + "】加入成功........");
	//			return muc;
	//		} catch (XMPPException e) {
	//			e.printStackTrace();
	//			L.i("MultiUserChat", "会议室【" + roomsName + "】加入失败........");
	//			return null;
	//		}
	//	}

	//	调用这个两个方法都可以获取到MultiUserChat，根据需求选择一个就可以。
	//	利用MultiUserChat对象调用sendMessage()方法即可，很容易吧~
	//	try {  
	//	    multiUserChat.sendMessage(message);  
	//	} catch (XMPPException e) {  
	//	    e.printStackTrace();  
	//	}

	//	添加监听器，每个会议室聊天对象都要添加一个消息监听器,为了避免重复监听
	//	应该把会议室聊天对象放在一个集合当中，需要用到的时候取出来用即可。
	//	multiUserChat.addMessageListener(new TaxiMultiListener());

	//	其次就是给连接设置监听器了，最好放在登录方法里，关闭连接方法里移除监听
	//	// 添加連接監聽  
	//	TaxiConnectionListener connectionListener = new TaxiConnectionListener();  
	//	getConnection().addConnectionListener(connectionListener);  

	//	connection.removeConnectionListener(connectionListener);
} public class MyScrollView extends ViewGroup {
	private Context ctx;

	public MyScrollView(Context context) {
		super(context);
		this.ctx = context;
		init();
	}

	private void init() {
		scroller = new Scroller(ctx);
		gestureDetector = new GestureDetector(ctx, new OnGestureListener() {

			@Override
			public boolean onSingleTapUp(MotionEvent e) {//有一个手指抬起的时候
				// TODO Auto-generated method stub
				return false;
			}

			@Override
			public void onShowPress(MotionEvent e) {//当发生按下事件的时候
				// TODO Auto-generated method stub

			}

			/**
			 * 正常滑动屏幕时的回调方法
			 */
			@Override
			public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
				scrollBy((int) distanceX, 0);
				return false;
			}

			@Override
			public void onLongPress(MotionEvent e) {//长按事件的时候
				// TODO Auto-generated method stub

			}

			/**
			 * 发生快速滑动时的回调方法
			 */
			@Override
			public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {

				isFling = true;//处理和onTouchEvent事件里面的抬起事件的冲突问题

				if (velocityX > 0 && curId > 0) {//快速向右滑
					moveToDest(curId - 1);
				} else if (velocityX < 0 && curId < getChildCount()) {//快速向左滑
					moveToDest(curId + 1);
				} else {//其他乱滑动，统一默认处理
					moveToDest();
				}

				return false;
			}

			@Override
			public boolean onDown(MotionEvent e) {
				// TODO Auto-generated method stub
				return false;
			}
		});

	}

	/**
	 * 对子view进行测量大小 view显示出来的几个步骤： 1、构造方法 2、测量大小 3、指定位置 4、绘制出来
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		for (int i = 0; i < getChildCount(); i++) {
			View view = getChildAt(i);
			view.measure(widthMeasureSpec, heightMeasureSpec);
		}
	}

	/**
	 * 对子view进行排列布局
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		for (int i = 0; i < getChildCount(); i++) {
			View view = getChildAt(i);
			view.layout(i * getWidth(), 0, (i + 1) * getWidth(), getHeight());
		}
	}

	private GestureDetector gestureDetector;

	private Scroller scroller;

	/**
	 * 当前屏幕显示的子view的下标
	 */
	private int curId;

	/**
	 * 是否发生快速滑动
	 */
	private boolean isFling = false;

	private float lastX;
	private float lastY;

	/**
	 * 中断Touch事件
	 */
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {

		//这个是为了解决一个突然跳动的bug，因为在中断事件的过程中,子View获得了down事件这个时候突然中断 但是父view却没有down事件导致初始坐标为0，出现弹跳bug
		gestureDetector.onTouchEvent(ev);

		boolean result = false;

		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			lastX = ev.getX();//记录按下的坐标值
			lastY = ev.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			int distanceX = (int) Math.abs(ev.getX() - lastX);//记录移动的偏移量
			int distanceY = (int) Math.abs(ev.getY() - lastY);

			//如果左右的偏移量 大于 上下的偏移量 并且    偏移量大于10(用来表明不是手指抖动)个像素  父View就执行中断操作
			if (distanceX > distanceY && distanceX > 10) {
				result = true;
			} else {
				result = false;
			}

			break;
		case MotionEvent.ACTION_UP:
			break;
		}

		return result;
	}

	/**
	 * 添加触摸事件
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {

		gestureDetector.onTouchEvent(event);

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN://按下
			break;
		case MotionEvent.ACTION_MOVE://移动
			break;
		case MotionEvent.ACTION_UP://抬起

			if (!isFling) {
				moveToDest();
			}
			isFling = false;
			break;
		}

		return true;
	}

	/**
	 * 将viewGroup的内容移动到适当的位置上
	 */
	private void moveToDest() {
		int destId = (getScrollX() + getWidth() / 2) / getWidth();
		moveToDest(destId);
	}

	/**
	 * 将指定下标的子view移动到屏幕上来
	 * 
	 * @param destId 子view下标
	 */
	public void moveToDest(int destId) {

		if (destId > getChildCount() - 1) {//处理下标超过边界的问题
			destId = getChildCount() - 1;
		}

		curId = destId;

		if (changedListener != null) {
			changedListener.changedTo(curId);
		}

		int distance = destId * getWidth() - getScrollX();
		//scroller.startScroll(getScrollX(), 0, distance, 0);//使用默认完成时间250ms
		/**
		 * 处理下速度问题(让播放时间与距离成正比)
		 */
		scroller.startScroll(getScrollX(), 0, distance, 0, Math.abs(distance));

		invalidate();//刷新视图     会执行  computeScroll() 这个方法 
	}

	@Override
	public void computeScroll() {//当父类要去更新子类的ScrollX,ScrollY的时候调用该方法
		if (scroller.computeScrollOffset()) {//是否还有偏移量，判断动画结束了没
			scrollTo(scroller.getCurrX(), 0);
			invalidate();
		}
	}

	/**
	 * 对外暴露一个接口
	 * 
	 * @author lijian
	 * 
	 */
	public interface IPageChangedListener {
		public void changedTo(int pageId);
	}

	private IPageChangedListener changedListener;

	public IPageChangedListener getChangedListener() {
		return changedListener;
	}

	public void setChangedListener(IPageChangedListener changedListener) {
		this.changedListener = changedListener;
	}

	/**
	 * 图片自动轮播的下标传递
	 * 
	 * @return
	 */
	public int getCurId() {
		return curId;
	}
} public interface IPageChangedListener {
	public void changedTo(int pageId);
}
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import net.cgt.weixin.R;
import net.cgt.weixin.db.dao.ChatInfoDao;
import net.cgt.weixin.domain.ChatEmoji;
import net.cgt.weixin.domain.ChatMsgEntity;
import net.cgt.weixin.domain.User;
import net.cgt.weixin.utils.AppToast;
import net.cgt.weixin.utils.DensityUtil;
import net.cgt.weixin.utils.FaceConversionUtil;
import net.cgt.weixin.utils.HandlerTypeUtils;
import net.cgt.weixin.utils.L;
import net.cgt.weixin.utils.LogUtil;
import net.cgt.weixin.view.adapter.ChatMsgAdapter;
import net.cgt.weixin.view.adapter.EmojiAdapter;
import net.cgt.weixin.view.manager.XmppManager;
import net.cgt.weixin.view.scrollView.MyScrollView;
import net.cgt.weixin.view.scrollView.MyScrollView.IPageChangedListener;
import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.XMPPException;
import android.app.ActionBar;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.support.v4.app.NavUtils;
import android.support.v4.app.TaskStackBuilder;
import android.text.Editable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.ScaleAnimation;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
					break;

				case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://触摸滚动状态
					L.i(LOGTAG, "触摸滚动状态");
					break;
				case OnScrollListener.SCROLL_STATE_FLING://惯性滚动状态
					L.i(LOGTAG, "惯性滚动状态");
					break;
				}
			}

			@Override
			public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
			}
		});
	}

	/**
	 * 获取并填充聊天数据
	 */
	private void fillData() {
		isLoading = true;
		mPb_chat_loading.setVisibility(View.VISIBLE);
		new Thread() {
			public void run() {
				List<ChatMsgEntity> list = dao.findPart(maxNumber, startIndex);
				findChatMsgCount = list.size();
				if (list.size() != 0) {
					if (mList_ChatMsgEntity == null) {
						mList_ChatMsgEntity = list;
					} else {
						mList_ChatMsgEntity.addAll(0, list);
					}
					handler.sendEmptyMessage(CHATMSGENTITY_DATA_FULL);
				} else {
					handler.sendEmptyMessage(CHATMSGENTITY_DATA_EMPTY);
				}
			};
		}.start();
	}

	private void initData() {
		imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
		vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
		IntentFilter filter = new IntentFilter("net.cgt.weixin.chat");
		registerReceiver(receiver, filter);// 注册一个广播接收者

		Animation sa = new ScaleAnimation(0.8f, 1.0f, 0.8f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
		Animation aa = new AlphaAnimation(0.1f, 1.0f);
		animationSet = new AnimationSet(true);
		animationSet.addAnimation(aa);
		animationSet.addAnimation(sa);
		animationSet.setDuration(100);
		mEt_chat_input.addTextChangedListener(watcher);
		mEt_chat_input.setOnClickListener(this);

		setSmilingfaceData();

		mList_ChatMsgEntity = new ArrayList<ChatMsgEntity>();
		dao = new ChatInfoDao(this);

		fillData();

		//		List<ChatMsgEntity> findPart = dao.findPart(maxNumber, startIndex);
		//		mList_ChatMsgEntity.addAll(findPart);
		//		mAdpt_chatMsg = new ChatMsgAdapter(this, mList_ChatMsgEntity);
		//		mLv_chat_showBox.setAdapter(mAdpt_chatMsg);
	}

	/**
	 * 设置笑脸被点击后的表情数据
	 */
	private void setSmilingfaceData() {
		mV_myScrollView = new MyScrollView(this);
		mList_emoji = FaceConversionUtil.getInstace().emojiLists;

		// 添加表情页
		mList_emojiAdapter = new ArrayList<EmojiAdapter>();
		mV_myScrollView.removeAllViews();
		for (int i = 0; i < mList_emoji.size(); i++) {
			//			GridView的一些特殊属性：
			//
			//			1.android:numColumns=”auto_fit”   //GridView的列数设置为自动
			//			2.android:columnWidth=”90dp "       //每列的宽度，也就是Item的宽度
			//			3.android:stretchMode=”columnWidth"//缩放与列宽大小同步
			//			4.android:verticalSpacing=”10dp”          //两行之间的边距
			//			5.android:horizontalSpacing=”10dp”      //两列之间的边距 
			//			6.android:cacheColorHint="#00000000" //去除拖动时默认的黑色背景
			//			7.android:listSelector="#00000000"        //去除选中时的黄色底色
			//			8.android:scrollbars="none"                   //隐藏GridView的滚动条
			//			9.android:fadeScrollbars="true"             //设置为true就可以实现滚动条的自动隐藏和显示
			//			10.android:fastScrollEnabled="true"      //GridView出现快速滚动的按钮(至少滚动4页才会显示)
			//			11.android:fadingEdge="none"                //GridView衰落(褪去)边缘颜色为空，缺省值是vertical。(可以理解为上下边缘的提示色)
			//			12.android:fadingEdgeLength="10dip"   //定义的衰落(褪去)边缘的长度
			//			13.android:stackFromBottom="true"       //设置为true时，你做好的列表就会显示你列表的最下面
			//			14.android:transcriptMode="alwaysScroll" //当你动态添加数据时，列表将自动往下滚动最新的条目可以自动滚动到可视范围内
			//			15.android:drawSelectorOnTop="false"  //点击某条记录不放，颜色会在记录的后面成为背景色,内容的文字可见(缺省为false)
			//			
			GridView view = new GridView(this);
			EmojiAdapter adapter = new EmojiAdapter(this, mList_emoji.get(i));
			view.setAdapter(adapter);
			mList_emojiAdapter.add(adapter);
			view.setOnItemClickListener(this);
			view.setNumColumns(7);
			view.setBackgroundColor(Color.TRANSPARENT);
			//			view.setHorizontalSpacing(1); //两列之间的边距
			//			view.setVerticalSpacing(10);//两行之间的边距
			view.setStretchMode(GridView.STRETCH_COLUMN_WIDTH);//缩放与列宽大小同步
			view.setCacheColorHint(0);//去除拖动时默认的黑色背景
			//						view.setPadding(5, 5, 5, 5);
			view.setSelector(new ColorDrawable(Color.TRANSPARENT));
			LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
			view.setLayoutParams(params);
			view.setGravity(Gravity.CENTER);
			mV_myScrollView.addView(view);
		}

		mLl_chat_smilingface_body.removeAllViews();
		mLl_chat_smilingface_body.addView(mV_myScrollView);//将MyScrollView添加到内容显示区

		RadioGroup.LayoutParams params_rb = new RadioGroup.LayoutParams(DensityUtil.dip2px(this, 8), DensityUtil.dip2px(this, 8));