public static enum Mode {

	/**
	 * Disable all Pull-to-Refresh gesture and Refreshing handling
	 */
	DISABLED(0x0),

	/**
	 * Only allow the user to Pull from the start of the Refreshable View to
	 * refresh. The start is either the Top or Left, depending on the
	 * scrolling direction.
	 */
	PULL_FROM_START(0x1),

	/**
	 * Only allow the user to Pull from the end of the Refreshable View to
	 * refresh. The start is either the Bottom or Right, depending on the
	 * scrolling direction.
	 */
	PULL_FROM_END(0x2),

	/**
	 * Allow the user to both Pull from the start, from the end to refresh.
	 */
	BOTH(0x3),

	/**
	 * Disables Pull-to-Refresh gesture handling, but allows manually
	 * setting the Refresh state via
	 * {@link PullToRefreshBase#setRefreshing() setRefreshing()}.
	 */
	MANUAL_REFRESH_ONLY(0x4);

	/**
	 * @deprecated Use {@link #PULL_FROM_START} from now on.
	 */
	public static Mode PULL_DOWN_TO_REFRESH = Mode.PULL_FROM_START;

	/**
	 * @deprecated Use {@link #PULL_FROM_END} from now on.
	 */
	public static Mode PULL_UP_TO_REFRESH = Mode.PULL_FROM_END;

	/**
	 * Maps an int to a specific mode. This is needed when saving state, or
	 * inflating the view from XML where the mode is given through a attr
	 * int.
	 * 
	 * @param modeInt
	 *            - int to map a Mode to
	 * @return Mode that modeInt maps to, or PULL_FROM_START by default.
	 */
	static Mode mapIntToValue(final int modeInt) {
		for (Mode value : Mode.values()) {
			if (modeInt == value.getIntValue()) {
				return value;
			}
		}

		// If not, return default
		return getDefault();
	}

	static Mode getDefault() {
		return PULL_FROM_START;
	}

	private int mIntValue;

	// The modeInt values need to match those from attrs.xml
	Mode(int modeInt) {
		mIntValue = modeInt;
	}

	/**
	 * @return true if the mode permits Pull-to-Refresh
	 */
	boolean permitsPullToRefresh() {
		return !(this == DISABLED || this == MANUAL_REFRESH_ONLY);
	}

	/**
	 * @return true if this mode wants the Loading Layout Header to be shown
	 */
	public boolean showHeaderLoadingLayout() {
		return this == PULL_FROM_START || this == BOTH;
	}

	/**
	 * @return true if this mode wants the Loading Layout Footer to be shown
	 */
	public boolean showFooterLoadingLayout() {
		return this == PULL_FROM_END || this == BOTH
				|| this == MANUAL_REFRESH_ONLY;
	}

	int getIntValue() {
		return mIntValue;
	}

} public class LoginUserInfo {
	private UserInfo UserInfo;
	private String userId = "";
	private String password = "";

	public LoginUserInfo(String userid, String password) {
		setUserId(userid);
		setPassword(password);
	}

	public LoginUserInfo(UserInfo userInfo) {
		setUserInfo(userInfo);
	}

	public UserInfo getUserInfo() {
		return UserInfo;
	}

	public void setUserInfo(UserInfo userInfo) {
		UserInfo = userInfo;
		if (userInfo != null) {
			userId = userInfo.getId();
		}
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

} public class Message {
	private int id = Constant.MESSAGE_ID_UNDIFINED;
	private int msgid = Constant.MESSAGE_ID_UNDIFINED;
	private String floginid;
	private String tologinid;
	private String folder;
	private String subject;
	private long sendtime;
	private long writetime;
	private int hasview;
	private int isadmin;
	private String message;
	private int sessionid = Constant.MESSAGESESSION_ID_UNDIFINED;
	private int state = Constant.MESSAGE_STATE_SENDING;

	public int getState() {
		return state;
	}

	public void setState(int state) {
		this.state = state;
	}

	public int getId() {
		return id;
	}

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

	public String getFloginid() {
		return floginid;
	}

	public void setFloginid(String floginid) {
		this.floginid = floginid;
	}

	public String getTologinid() {
		return tologinid;
	}

	public void setTologinid(String tologinid) {
		this.tologinid = tologinid;
	}

	public String getFolder() {
		return folder;
	}

	public void setFolder(String folder) {
		this.folder = folder;
	}

	public String getSubject() {
		return subject;
	}

	public void setSubject(String subject) {
		this.subject = subject;
	}

	public long getSendtime() {
		return sendtime;
	}

	public void setSendtime(long sendtime) {
		this.sendtime = sendtime;
	}

	public long getWritetime() {
		return writetime;
	}

	public void setWritetime(long writetime) {
		this.writetime = writetime;
	}

	public int getHasview() {
		return hasview;
	}

	public void setHasview(int hasview) {
		this.hasview = hasview;
	}

	public int getIsadmin() {
		return isadmin;
	}

	public void setIsadmin(int isadmin) {
		this.isadmin = isadmin;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public int getSessionid() {
		return sessionid;
	}

	public void setSessionid(int sessionid) {
		this.sessionid = sessionid;
	}

	public int getMsgid() {
		return msgid;
	}

	public void setMsgid(int msgid) {
		this.msgid = msgid;
	}

	@Override
	public String toString() {
		return "Message [id=" + id + ", msgid=" + msgid + ", floginid=" + floginid + ", tologinid=" + tologinid + ", folder=" + folder
				+ ", subject=" + subject + ", sendtime=" + sendtime + ", writetime=" + writetime + ", hasview=" + hasview + ", isadmin="
				+ isadmin + ", message=" + message + ", sessionid=" + sessionid + ", state=" + state + "]";
	}

} public class MessageSession {
	private int id = Constant.MESSAGESESSION_ID_UNDIFINED;
	private String userid;
	private String owner;
	
	public String getUserid() {
		return userid;
	}

	public void setUserid(String userid) {
		this.userid = userid;
	}

	public int getId() {
		return id;
	}

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

	public String getOwner() {
		return owner;
	}

	public void setOwner(String owner) {
		this.owner = owner;
	}


} public class UserInfo {
	private String id;
	private String name;
	private String email;
	private String birthday;
	private String city;
	private String description;
	private Integer sex;
	private int isFriend;
	/**
	 * 头像
	 */
	private String protrait;

	public String getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getProtrait() {
		return protrait;
	}

	public void setProtrait(String protrait) {
		this.protrait = protrait;
	}

	public String getBirthday() {
		return birthday;
	}

	public void setBirthday(String birthday) {
		this.birthday = birthday;
	}

	public String getCity() {
		return city;
	}

	public void setCity(String city) {
		this.city = city;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Integer getSex() {
		return sex;
	}

	public void setSex(Integer sex) {
		this.sex = sex;
	}

	public int getIsFriend() {
		return isFriend;
	}

	public boolean IsFriend() {
		return isFriend != 0;
	}

	public void setIsFriend(int isFriend) {
		this.isFriend = isFriend;
	}

} public class LoginService extends BaseService {
	private final String TAG = LoginService.class.getSimpleName();
	private static LoginService instance;
	/**
	 * MSG 编号 100~200
	 */
	public final static int MSG_LOGIN_SUCCESS = 100;
	public final static int MSG_LOGIN_FAILD = 101;
	public final static int MSG_REGISTE_SUCCESS = 110;
	public final static int MSG_REGISTE_FAILD = 111;
	public final static int MSG_FORGOTPASSWORD_SUCCESS = 120;
	public final static int MSG_FORGOTPASSWORD_FAILD = 121;
	public final static int MSG_LOGOUT_SUCCESS = 131;
	// api地址
	private final String LOGIN_URL = Constant.SERVER_ADD + "/app/login.php";
	private final String REGISTE_URL = Constant.SERVER_ADD + "/app/registe.php";
	private final String FORGOTPASSWORD_URL = Constant.SERVER_ADD + "/app/forgotpassword.php";

	private LoginService(Context context) {
		super(context);
	}

	private static LoginService getInstance(Context context) {
		if (instance == null) {
			instance = new LoginService(context);
		}
		return instance;
	}

	public static LoginService getInstance() {
		return getInstance(AppContext.getInstance());
	}

	/**
	 * 是否已经登陆
	 * 
	 * @return
	 */
	public boolean isLogined() {
		return getServiceManager().getUserService().getCurrentLoginUser() != null;
	}

	/**
	 * 登录 在调用登录后，会再去调用获取用户信息
	 * 
	 * @param username
	 * @param password
	 * @param handler
	 *            用来接收回调消息用的handler
	 */
	public void login(final String username, final String password, final Handler handler) {
		Log.i(TAG, "#login:" + username);

		Map<String, String> params = new HashMap<String, String>();
		params.put("action", "login");
		params.put("username", username);
		params.put("password", password);

		Request request = new JsonObjectRequest(LOGIN_URL, params, new ResultResponeListener() {

			@Override
			protected void handeResponeSuccess(Respone result) {
				//登录成功后，后台更新好友列表信息
				UserService.getInstance().syncFrieds(null);
				
				final Message msg = getMessage(MSG_LOGIN_SUCCESS);

				//更新当前登录用户的个人信息
				getServiceManager().getUserService().syncUserInfo(username, new Handler(new Handler.Callback() {

					@Override
					public boolean handleMessage(Message syncmsg) {
						switch (syncmsg.what) {
						case UserService.MSG_SYNC_USERINFO_SUCCESS:
							UserInfo userInfo = (UserInfo) syncmsg.obj;
							LoginUserInfo loginUserInfo = new LoginUserInfo(userInfo);
							loginUserInfo.setPassword(password);

							getServiceManager().getUserService().setCurrentLoginUser(loginUserInfo);
							break;

						default:
							break;
						}
						// TODO 需要处理同步信息发生的错误？
						sendHandlerMessage(handler, msg);
						return true;
					}
				}));
			}

			@Override
			protected void handeResponeFaild(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_LOGIN_FAILD));
			}

		}, getErrorListener(handler));

		getHttpRequesttQueue().add(request);
	}

	/**
	 * 注销
	 * 
	 * @param handler
	 *            用来接收回调消息用的handler
	 */
	public void logout(final Handler handler) {
		if (!isLogined()) {
			handler.sendMessage(handler.obtainMessage(MSG_ERROR, new Exception("you has not login!")));
		} else {
			Log.i(TAG, "#logout");
			// TODO 注销,需要调用服务器接口？
			getServiceManager().getUserService().setCurrentLoginUser(null);
			ConfigHelper.getInstance().cleanCookie();
			//清空好友关系
			UserService.getInstance().clearFreindRelationship();
			handler.sendMessage(handler.obtainMessage(MSG_LOGOUT_SUCCESS));
		}
	}

	/**
	 * 忘记密码，调用远程忘记密码发送验证邮件
	 * 
	 * @param emial
	 * @param handler
	 */
	public void forgotpassword(String emial, final Handler handler) {
		Map<String, String> params = new HashMap<String, String>();
		params.put("email", emial);

		Request request = new JsonObjectRequest(FORGOTPASSWORD_URL, params, new ResultResponeListener() {

			@Override
			protected void handeResponeSuccess(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_FORGOTPASSWORD_SUCCESS));
			}

			@Override
			protected void handeResponeFaild(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_FORGOTPASSWORD_FAILD));
			}
		}, getErrorListener(handler));

		getHttpRequesttQueue().add(request);
	}

	/**
	 * 注册
	 * 
	 * @param email
	 * @param password
	 * @param handler
	 */
	public void registe(String email, String password, final Handler handler) {
		Log.i(TAG, "#registe:" + email);
		Map<String, String> params = new HashMap<String, String>();
		params.put("email", email);
		params.put("password", password);

		Request request = new JsonObjectRequest(REGISTE_URL, params, new ResultResponeListener() {

			@Override
			protected void handeResponeSuccess(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_REGISTE_SUCCESS));
			}

			@Override
			protected void handeResponeFaild(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_REGISTE_FAILD));
			}

		}, getErrorListener(handler));

		getHttpRequesttQueue().add(request);
	}

	public void saveLoginUserInfoConfig(LoginUserInfo loginUserInfo) {
		ConfigHelper.getInstance().saveLoginUserInfoConfig(loginUserInfo);
	}

	/**
	 * 读取登录信息, 读取出来的 LoginUserInfo 里面User是空的
	 * 
	 * @return
	 */
	public LoginUserInfo loadLoginUserInfoConfig() {
		return ConfigHelper.getInstance().loadLoginUserInfoConfig();
	}

	/**
	 * 自动登录 读取 缓存的配置文件然后登录
	 * 
	 * @param handler
	 *            ,完成后登录事件处理
	 */
	public void autoLogin() {
		if (!isAllowAutoLogin()) {
			return;
		}
		LoginUserInfo loginConfig = loadLoginUserInfoConfig();
		if (!TextUtils.isEmpty(loginConfig.getUserId())) {
			// 因为本地有数据先运行 “离线登陆”
			final UserService userService = getServiceManager().getUserService();
			UserInfo userInfo = userService.getUserInfo(loginConfig.getUserId());
			if(userInfo == null){
				//当本地数据库没有找到这个用户数据的时候，不自动登录
				return;
			}
			
			loginConfig.setUserInfo(userInfo);
			userService.setCurrentLoginUser(loginConfig);

			// 下面真正验证登陆
			Log.i(TAG, "#autoLogin");
			login(loginConfig.getUserId(), loginConfig.getPassword(), new Handler(new Handler.Callback() {

				@Override
				public boolean handleMessage(Message msg) {
					switch (msg.what) {
					case MSG_LOGIN_FAILD:// 登陆失败
						userService.setCurrentLoginUser(null);
						break;
					case MSG_ERROR:
						// TODO 其他错误 需要处理？比如解析json
						break;
					default:
						break;
					}
					return false;
				}
			}));
		}
	}

	/**
	 * 是否允许自动登录
	 * 
	 * @return
	 */
	public boolean isAllowAutoLogin() {
		return ConfigHelper.getInstance().isAllowAutoLogin();
	}
} public class MessageService extends BaseService {
	private final String TAG = MessageService.class.getSimpleName();
	private ContentResolver mContentResolver;
	private static MessageService mInstance;
	private final int mQueryCount = 20;

	private final String URL_LIST_MESSAGE = Constant.SERVER_ADD + "/app/pm.php";
	private final String URL_READ_MESSAGE = Constant.SERVER_ADD + "/app/pm.php";
	private final String URL_SEND_MESSAGE = Constant.SERVER_ADD + "/app/pm.php";
	private final String URL_DELETE_MESSAGE = Constant.SERVER_ADD + "/app/pm.php";

	public final static int MSG_SYNC_MESSAGE_SUCCESS = 400;
	public final static int MSG_SYNC_MESSAGE_FAILD = 401;
	public final static int MSG_SEND_MESSAGE_SUCCESS = 410;
	public final static int MSG_SEND_MESSAGE_FAILD = 411;
	public final static int MSG_QUERY_MESSAGE_SUCCESS = 420;
	public final static int MSG_QUERY_MESSAGE_FAILD = 421;

	private MessageService(Context context) {
		super(context);
		mContentResolver = context.getContentResolver();
	}

	public static MessageService getInstance() {
		return getInstance(AppContext.getInstance());
	}

	public static MessageService getInstance(Context context) {
		if (mInstance == null) {
			mInstance = new MessageService(context);
		}
		return mInstance;
	}

	/**
	 * 获取 查询数据的返回条数
	 * 
	 * @return
	 */
	public int getQueryCount() {
		return mQueryCount;
	}

	/**
	 * 获取MessionSession
	 * 
	 * @param sessionid
	 * @return
	 */
	public MessageSession getMessageSession(int sessionid) {
		Cursor cursor = queryMessageSession(sessionid);
		MessageSession session = null;
		if (cursor != null) {
			if (cursor.moveToFirst()) {
				session = getMessageSessionEntry(cursor);
			}
			cursor.close();
		}
		return session;
	}

	/**
	 * 转换成实体
	 * 
	 * @param cursor
	 * @return
	 */
	public MessageSession getMessageSessionEntry(Cursor cursor) {
		// TODO 实现转换
		MessageSession session = new MessageSession();
		session.setId(cursor.getInt(cursor.getColumnIndex(MessageSessionColumns._ID)));
		session.setUserid(cursor.getString(cursor.getColumnIndex(MessageSessionColumns.USERID)));
		session.setOwner(cursor.getString(cursor.getColumnIndex(MessageSessionColumns.OWNER)));
		return session;
	}

	public Cursor queryMessageSession() {
		// TODO 实现查询
		String orderBy = MessageSessionColumns._ID + " DESC LIMIT " + mQueryCount;
		Cursor cursor = mContentResolver.query(Constant.CONTENT_URI_MESSAGE_SESSION_PROVIDER, null, MessageSessionColumns.OWNER + "=?",
				new String[] { UserService.getInstance().getCurrentLoginUserId() }, orderBy);
		return cursor;
	}

	public Cursor queryMessageSession(int sessionid) {
		Cursor cursor = mContentResolver.query(
				Uri.withAppendedPath(Constant.CONTENT_URI_MESSAGE_SESSION_PROVIDER, String.valueOf(sessionid)), null, null, null, null);
		return cursor;
	}

	/**
	 * 是否存在比这个时间点更前的消息
	 * 
	 * @param time
	 * @param sessionid
	 * @return
	 */
	private boolean hasPreMessage(long time, int sessionid) {
		String orderBy = MessageColumns.SENDTIME + " ASC ";
		Cursor cursor = mContentResolver.query(Constant.CONTENT_URI_MESSAGE_PROVIDER, null, MessageColumns.SENDTIME + "<? AND "
				+ MessageColumns.SESSIONID + "=? AND " + MessageSessionColumns.OWNER + "=?",
				new String[] { String.valueOf(time), String.valueOf(sessionid), UserService.getInstance().getCurrentLoginUserId() },
				orderBy);
		boolean hasPre = cursor.getCount() > 0;
		cursor.close();
		return hasPre;
	}

	/**
	 * 获取 这个时间点 往前推20条消息的发送时间
	 * 
	 * @param time
	 * @param sessionid
	 * @return
	 */
	private long getPreMessageSendTime(final long time, int sessionid) {
		// 查询往前20条消息的id
		String orderby = MessageColumns.SENDTIME + " DESC LIMIT " + mQueryCount;
		Cursor c = mContentResolver.query(Constant.CONTENT_URI_MESSAGE_PROVIDER, null, MessageColumns.SENDTIME + "<? AND "
				+ MessageColumns.SESSIONID + "=?", new String[] { String.valueOf(time), String.valueOf(sessionid) }, orderby);
		// 往前推20条的发送时间
		long preSendTime = 0;
		if (c.moveToLast()) {
			preSendTime = c.getLong(c.getColumnIndex(MessageColumns.SENDTIME));
		}
		c.close();
		return preSendTime;
	}

	/**
	 * 获取消息列表loader </br>只会加载最后20条
	 * 
	 * @param sessionid
	 * @return
	 */
	public CursorLoader getMessageLoader(int sessionid) {
		long preSendTime = getPreMessageSendTime(System.currentTimeMillis(), sessionid);

		String orderby = MessageColumns.SENDTIME + " ASC";
		return new CursorLoader(mContext, Constant.CONTENT_URI_MESSAGE_PROVIDER, null, MessageColumns.SENDTIME + ">=? AND "
				+ MessageColumns.SESSIONID + "=?", new String[] { String.valueOf(preSendTime), String.valueOf(sessionid) }, orderby);
	}

	/**
	 * 查询 这个时间点 往前推 20条消息的数据（包括 20条之后的数据）
	 * 
	 * @param time
	 * @param sessionid
	 * @return
	 */
	private Cursor queryPreMessage(final long time, int sessionid) {

		long preSendTime = getPreMessageSendTime(time, sessionid);

		String orderby = MessageColumns.SENDTIME + " ASC";
		return mContentResolver.query(Constant.CONTENT_URI_MESSAGE_PROVIDER, null, MessageColumns.SENDTIME + ">=? AND "
				+ MessageColumns.SESSIONID + "=?", new String[] { String.valueOf(preSendTime), String.valueOf(sessionid) }, orderby);
	}

	/**
	 * 把时间点往前推，直到查询到 有20数据以后，在handler中返回 包括20条消息以后的消息。
	 * 
	 * @param time
	 *            发送时间
	 * @param sessionid
	 * @param handler
	 *            如果 查询到 cursor.getCount() == 0那么 去拉去服务器的数据，并通知 handler，这个时候
	 */
	public void queryMessageByTime(final long time, final int sessionid, final MessageQueryHandler handler) {
		if (hasPreMessage(time, sessionid)) {
			// 没有查询到时到服务器上去拉取数据
			// 获取本地最后一个发送时间最前的 msgid
			String qOrderBy = MessageColumns.SENDTIME + " DESC LIMIT 1";
			Cursor c = mContentResolver.query(Constant.CONTENT_URI_MESSAGE_PROVIDER, null, MessageColumns.MSGID + "!=?",
					new String[] { String.valueOf(Constant.MESSAGE_ID_UNDIFINED) }, qOrderBy);

			String id = null;
			if (c.moveToFirst()) {
				id = c.getString(c.getColumnIndex(MessageColumns.MSGID));
			}
			c.close();

			final String lastid = id;
			// 同步服务器消息
			syncMessage(lastid, new MessageSyncHandler(lastid, new BaseServiceHandler.Callback<String>() {
				@Override
				public void complate(boolean success, String msgid, String message) {
					if (success) {
						// 同步完成后 查询本地消息并返回
						Cursor c = queryPreMessage(time, sessionid);
						android.os.Message handlerMsg = new android.os.Message();
						handlerMsg.what = MSG_QUERY_MESSAGE_SUCCESS;
						handlerMsg.obj = c;
						handler.sendMessage(handlerMsg);
					} else {
						// 失败了发送查询失败的消息
						handler.obtainMessage(MSG_QUERY_MESSAGE_FAILD);
					}
				}
			}));
		} else {
			android.os.Message handlerMsg = new android.os.Message();
			handlerMsg.what = MSG_QUERY_MESSAGE_SUCCESS;
			handlerMsg.obj = queryPreMessage(time, sessionid);
			handler.sendMessage(handlerMsg);
		}
	}

	/**
	 * 拉取服务器最新的消息
	 * 
	 * @param handler
	 */
	public void syncMessage(final Handler handler) {
		syncMessage(null, handler);
	}

	/**
	 * 拉取服务器的msgid 之前的消息
	 * 
	 * @param msgid
	 *            msgid == null 时从服务器上拉取所有消息
	 * @param handler
	 */
	public void syncMessage(final String msgid, final Handler handler) {
		//检查登录
		if(!checkLogin(handler)){
			return;
		}
		
		Map<String, String> params = new HashMap<String, String>();
		params.put("action", "list");
		// TODO 不拉取所有列表只拉取 某个msgid 以后的 数据
		if (TextUtils.isEmpty(msgid)) {
			params.put("all", "true");
		} else {
			params.put("msgid", msgid);
		}

		Request request = new JsonArrayRequest(URL_LIST_MESSAGE, params, new Response.Listener<JSONArray>() {

			@Override
			public void onResponse(JSONArray json) {
				// 这里比较耗时 放入到 aysnctask中执行
				AsyncTask handleTask = new AsyncTask<JSONArray, Integer, android.os.Message>() {

					@Override
					protected android.os.Message doInBackground(JSONArray... params) {
						android.os.Message handlerMsg = null;
						try {
							JSONArray jsonarray = params[0];
							List<Message> messages = HttpHelper.getJsonArray(jsonarray, new TypeToken<List<Message>>() {
							});
							saveServerMessages(messages);
							handlerMsg = handler.obtainMessage(MSG_SYNC_MESSAGE_SUCCESS);
						} catch (Exception e) {
							Log.e(TAG, "syncMessage error:" + msgid, e);
							handlerMsg = handler.obtainMessage(MSG_SYNC_MESSAGE_FAILD);
						}
						return handlerMsg;
					}

					@Override
					protected void onPostExecute(android.os.Message result) {
						result.sendToTarget();
						super.onPostExecute(result);
					}
				};

				handleTask.execute(new JSONArray[] { json });
			}
		}, getErrorListener(handler));
		request.setShouldCache(false);
		getHttpRequesttQueue().add(request);
	}

	/**
	 * 获取消息的contentvalues
	 * 
	 * @param msg
	 * @return
	 */
	private ContentValues getMessageContentValues(Message msg) {
		// 获取messageSessionid
		final int sessionid = getMessageSessionId(msg);
		msg.setSessionid(sessionid);

		ContentValues values = new ContentValues();

		values.put(MessageColumns.MSGID, msg.getMsgid());
		values.put(MessageColumns.FLOGINID, msg.getFloginid());
		values.put(MessageColumns.TOLOGINID, msg.getTologinid());
		values.put(MessageColumns.FOLDER, msg.getFolder());
		values.put(MessageColumns.SUBJECT, msg.getSubject());
		values.put(MessageColumns.SENDTIME, msg.getSendtime());
		values.put(MessageColumns.WRITETIME, msg.getWritetime());
		values.put(MessageColumns.HASVIEW, msg.getHasview());
		values.put(MessageColumns.ISADMIN, msg.getIsadmin());
		values.put(MessageColumns.MESSAGE, msg.getMessage());
		values.put(MessageColumns.STATE, msg.getState());
		values.put(MessageColumns.SESSIONID, msg.getSessionid());
		return values;
	}

	/**
	 * 保存服务器的消息到本地数据库
	 * 
	 * @param messages
	 */
	public void saveServerMessages(Collection<Message> messages) {
		// 插入数据到数据库
		for (Message msg : messages) {
			msg.setState(Constant.MESSAGE_STATE_SENED);
			// 根据 msgid 判断是否应该插入消息
			Cursor c = mContentResolver.query(Constant.CONTENT_URI_MESSAGE_PROVIDER, null, MessageColumns.MSGID + "=?",
					new String[] { String.valueOf(msg.getMsgid()) }, null);
			if (c != null && c.getCount() == 0) {
				ContentValues values = getMessageContentValues(msg);
				mContentResolver.insert(Constant.CONTENT_URI_MESSAGE_PROVIDER, values);
			}
			c.close();
		}
	}

	/**
	 * 保存 消息
	 * 
	 * @param msg
	 * @return
	 */
	public int saveMessage(Message msg) {
		ContentValues values = getMessageContentValues(msg);
		int id = Constant.MESSAGE_ID_UNDIFINED;

		if (msg.getId() != Constant.MESSAGE_ID_UNDIFINED) {// 更新
			mContentResolver.update(Uri.withAppendedPath(Constant.CONTENT_URI_MESSAGE_PROVIDER, String.valueOf(msg.getId())), values, null,
					null);
			id = msg.getId();
		} else {
			Uri uri = mContentResolver.insert(Constant.CONTENT_URI_MESSAGE_PROVIDER, values);
			try {
				id = Integer.valueOf(uri.getPathSegments().get(0));
			} catch (Exception e) {
				Log.e(TAG, "insertMessage", e);
			}
		}
		return id;
	}

	/**
	 * 获取这个用户对应的 sessionid，如果没有就会新增一条session记录
	 * 
	 * @param userid
	 * @return
	 */
	public int getMessageSessionId(String userid) {
		Message msg = buildSendMessage(userid, null);
		return getMessageSessionId(msg);
	}

	/**
	 * 获取这个消息的 sessionid，如果本地没有这个session，就会创建一个 session 数据插入到本地
	 * 
	 * @param msg
	 * @return
	 */
	private int getMessageSessionId(Message msg) {

		if (msg.getSessionid() != Constant.MESSAGESESSION_ID_UNDIFINED) {
			return msg.getSessionid();
		}

		int sessionid = Constant.MESSAGESESSION_ID_UNDIFINED;
		// 处理messageSession
		String targetUserId;
		if (Constant.MESSAGE_BOX_INBOX.equals(msg.getFolder())) {
			targetUserId = String.valueOf(msg.getFloginid());
		} else {
			targetUserId = String.valueOf(msg.getTologinid());
		}
		// 获取当前登录用户id
		String currentUserId = UserService.getInstance().getCurrentLoginUserId();
		
		Cursor sessionCursor = mContentResolver.query(Constant.CONTENT_URI_MESSAGE_SESSION_PROVIDER, null, MessageSessionColumns.USERID
				+ "=? AND "+MessageSessionColumns.OWNER+"=?", new String[] { targetUserId,currentUserId }, null);
		if (sessionCursor != null) {
			if (sessionCursor.getCount() == 0) {

				
				ContentValues values = new ContentValues();
				values.put(MessageSessionColumns.USERID, targetUserId);
				values.put(MessageSessionColumns.OWNER, currentUserId);
				Uri resultUri = mContentResolver.insert(Constant.CONTENT_URI_MESSAGE_SESSION_PROVIDER, values);
				if (resultUri != null) {
					try {
						sessionid = Integer.valueOf(resultUri.getPathSegments().get(0));
					} catch (Exception e) {
						Log.w(TAG, "getMessageSessionId parse insert uri " + resultUri);
					}
				}
			} else {
				if (sessionCursor.moveToFirst()) {
					sessionid = sessionCursor.getInt(sessionCursor.getColumnIndex(MessageSessionColumns._ID));
				}
			}
			sessionCursor.close();
		}
		return sessionid;
	}

	/**
	 * 转换 消息实体
	 * 
	 * @param cursor
	 * @return
	 */
	public Message getMessageEntry(Cursor cursor) {
		Message msg = new Message();
		msg.setId(cursor.getInt(cursor.getColumnIndex(MessageColumns._ID)));
		msg.setMsgid(cursor.getInt(cursor.getColumnIndex(MessageColumns.MSGID)));
		msg.setFloginid(cursor.getString(cursor.getColumnIndex(MessageColumns.FLOGINID)));
		msg.setTologinid(cursor.getString(cursor.getColumnIndex(MessageColumns.TOLOGINID)));
		msg.setFolder(cursor.getString(cursor.getColumnIndex(MessageColumns.FOLDER)));
		msg.setSubject(cursor.getString(cursor.getColumnIndex(MessageColumns.SUBJECT)));
		msg.setSendtime(cursor.getInt(cursor.getColumnIndex(MessageColumns.SENDTIME)));
		msg.setWritetime(cursor.getInt(cursor.getColumnIndex(MessageColumns.WRITETIME)));
		msg.setHasview(cursor.getInt(cursor.getColumnIndex(MessageColumns.HASVIEW)));
		msg.setIsadmin(cursor.getInt(cursor.getColumnIndex(MessageColumns.ISADMIN)));
		msg.setState(cursor.getInt(cursor.getColumnIndex(MessageColumns.STATE)));
		msg.setMessage(cursor.getString(cursor.getColumnIndex(MessageColumns.MESSAGE)));
		return msg;
	}

	/**
	 * 获取会话最后一条消息
	 * 
	 * @param messageSession
	 * @return
	 */
	public Message getLastMessage(MessageSession messageSession) {
		Message msg = null;
		int sessionid = messageSession.getId();
		String order = MessageColumns.SENDTIME + " DESC LIMIT 1";
		Cursor cursor = mContentResolver.query(Constant.CONTENT_URI_MESSAGE_PROVIDER, null, MessageColumns.SESSIONID + "=?",
				new String[] { String.valueOf(sessionid) }, order);
		try {
			if (cursor.moveToFirst()) {
				msg = getMessageEntry(cursor);
			}
		} catch (Exception e) {
			Log.w(TAG, e);
		} finally {
			cursor.close();
		}
		return msg;
	}

	/**
	 * 获取本地数据库时间点最前的一条已经发送或者接收的服务器消息
	 * 
	 * @return
	 */
	public Message getTopServerMessage() {
		String orderBy = MessageColumns.SENDTIME + " DESC LIMIT 1";
		Cursor cursor = mContentResolver.query(Constant.CONTENT_URI_MESSAGE_PROVIDER, null, MessageColumns.MSGID + "!=?",
				new String[] { String.valueOf(Constant.MESSAGE_ID_UNDIFINED) }, orderBy);
		Message message = null;
		if (cursor != null && cursor.moveToFirst()) {
			message = getMessageEntry(cursor);
			cursor.close();
		}
		return message;
	}

	/**
	 * 发送消息
	 * 
	 * @param targetUserid
	 *            对方id
	 * @param msg
	 *            消息内容
	 * @param handler
	 */
	public void sendMessage(Message msg, final Handler handler) {
		
		//检查是否登录
		if(!checkLogin(handler)){
			return;
		}
				
		// 插入到本地数据库
		msg.setState(Constant.MESSAGE_STATE_SENDING);
		int id = saveMessage(msg);
		msg.setId(id);
		final Message messageEntry = msg;

		Map<String, String> params = new HashMap<String, String>();
		params.put("action", "send");
		params.put("msgtoid", msg.getTologinid() == null ? new String() : msg.getTologinid());
		params.put("message", msg.getMessage() == null ? new String() : msg.getMessage());
		Request request = new JsonObjectRequest(URL_SEND_MESSAGE, params, new ResultResponeListener() {

			@Override
			protected void handeResponeSuccess(Respone result) {
				android.os.Message handlerMessage = getMessage();
				try {
					// 保存从服务器返回来的消息实体
					Message retrunMessage = (Message) HttpHelper.getJsonObject(result.getData(), Message.class);
					messageEntry.setMsgid(retrunMessage.getMsgid());
					messageEntry.setFolder(retrunMessage.getFolder());
					messageEntry.setSendtime(retrunMessage.getSendtime());
					messageEntry.setSubject(retrunMessage.getSubject());
					messageEntry.setHasview(retrunMessage.getHasview());
					messageEntry.setState(Constant.MESSAGE_STATE_SENED);

					handlerMessage.what = MSG_SEND_MESSAGE_SUCCESS;
				} catch (Exception e) {
					Log.e(TAG, "send message  parse msgid error" + messageEntry);
					handlerMessage.what = MSG_SEND_MESSAGE_FAILD;
				}
				saveMessage(messageEntry);
				handler.sendMessage(handlerMessage);
			}

			@Override
			protected void handeResponeFaild(Respone result) {
				android.os.Message handlerMessage = getMessage(MSG_SEND_MESSAGE_FAILD);
				messageEntry.setState(Constant.MESSAGE_STATE_FAILD);
				Log.e(TAG, "send message error:" + messageEntry);
				saveMessage(messageEntry);
				handler.sendMessage(handlerMessage);
			}
		}, getErrorListener(handler));
		request.setShouldCache(false);
		getHttpRequesttQueue().add(request);
	}

	/**
	 * 创建发送的消息
	 * 
	 * @param targetUserId
	 * @param msg
	 * @return
	 */
	public Message buildSendMessage(String targetUserId, String msg) {
		Message message = new Message();
		message.setFloginid(UserService.getInstance().getCurrentLoginUserId());
		message.setTologinid(targetUserId);
		message.setMessage(msg);
		message.setFolder(Constant.MESSAGE_BOX_OUTBOX);
		message.setState(Constant.MESSAGE_STATE_SENDING);
		message.setSendtime(System.currentTimeMillis());
		return message;
	}
} public class UserService extends BaseService {
	private final String TAG = UserService.class.getSimpleName();

	private final static String URL_GET_USER_INFO = Constant.SERVER_ADD + "/app/userInfo.php";
	private final static String URL_UPDATE_USER_INFO = Constant.SERVER_ADD + "/app/userInfo.php";
	private final static String URL_UPLOAD_USER_AVATAR = Constant.SERVER_ADD + "/app/userInfo_edit_avatar.php";
	private final static String URL_FRIEND = Constant.SERVER_ADD + "/app/space.php";

	/**
	 * MSG 编号 200~300
	 */
	public final static int MSG_SYNC_USERINFO_SUCCESS = 200;
	public final static int MSG_SYNC_USERINFO_FAILD = 201;
	public final static int MSG_UPLOAD_USER_AVATR_SUCCESS = 210;
	public final static int MSG_UPLOAD_USER_AVATR_FAILD = 211;
	public final static int MSG_UPDATE_USERINFO_SUCCESS = 220;
	public final static int MSG_UPDATE_USERINFO_FAILD = 221;
	public final static int MSG_QUERY_UNFRIEND_SUCCESS = 230;
	public final static int MSG_QUERY_UNFRIEND_FAILD = 231;
	public final static int MSG_NEW_FRIEND_SUCCESS = 240;
	public final static int MSG_NEW_FRIEND_FAILD = 241;
	public final static int MSG_SYNC_FRIEND_SUCCESS = 250;
	public final static int MSG_SYNC_FRIEND_FAILD = 251;
	public final static int MSG_DEL_FRIEND_SUCCESS = 260;
	public final static int MSG_DEL_FRIEND_FAILD = 261;
	
	private static UserService instance;
	private LoginUserInfo mCurrentLoginUser;

	// TODO 放到其他地方
	/**
	 * 性别资源
	 */
	public static Map<Integer, Integer> SEX_NAME_MAP = new HashMap<Integer, Integer>();
	static {
		SEX_NAME_MAP.put(Constant.SEX_UNKONW, R.string.sex_unknow);
		SEX_NAME_MAP.put(Constant.SEX_MAN, R.string.sex_man);
		SEX_NAME_MAP.put(Constant.SEX_WOMEN, R.string.sex_women);
	}

	public static Integer[] SEX_ARRAY = SEX_NAME_MAP.keySet().toArray(new Integer[3]);

	public static Map<Integer, Integer> SEX_DRAWABLE_MAP = new HashMap<Integer, Integer>();
	static {
		SEX_DRAWABLE_MAP.put(Constant.SEX_UNKONW, R.drawable.sex_unkonw);
		SEX_DRAWABLE_MAP.put(Constant.SEX_MAN, R.drawable.sex_man);
		SEX_DRAWABLE_MAP.put(Constant.SEX_WOMEN, R.drawable.sex_women);
	}

	private UserService(Context context) {
		super(context);
	}

	private static UserService getInstance(Context context) {
		if (instance == null) {
			instance = new UserService(context);
		}
		return instance;
	}

	public static UserService getInstance() {
		return getInstance(AppContext.getInstance());
	}

	/**
	 * 设置当前登录用户
	 * 
	 * @param loginUserInfo
	 */
	public void setCurrentLoginUser(LoginUserInfo loginUserInfo) {
		mCurrentLoginUser = loginUserInfo;
		getServiceManager().getLoginService().saveLoginUserInfoConfig(loginUserInfo);
	}

	/**
	 * 获取当前登录用户的id
	 * 如果没有登录就返回一个空字符串
	 * @return
	 */
	public String getCurrentLoginUserId(){
		if(getCurrentLoginUser() != null){
			return getCurrentLoginUser().getUserId();
		}else{
			return "";
		}
	}
	/**
	 * 获取当前登陆用户
	 * 
	 * @return
	 */
	public LoginUserInfo getCurrentLoginUser() {
		return mCurrentLoginUser;
	}

	/**
	 * 同步获取服务器用户的信息
	 * 
	 * @return
	 */
	public void syncUserInfo(String userid, final Handler handler) {
		Log.i(TAG, "#syncUserInfo:" + userid);
		// 从网络获取
		Map<String, String> params = new HashMap<String, String>();
		params.put("action", "get");
		params.put("userid", userid);

		Request request = new JsonObjectRequest(URL_GET_USER_INFO, params, new ResultResponeListener() {

			@Override
			protected void handeResponeSuccess(Respone result) {
				UserInfo userinfo = (UserInfo) HttpHelper.getJsonObject(result.getData(), UserInfo.class);
				// TODO 保存信息到本地数据库
				saveUserInfoLocal(userinfo);
				sendHandlerMessage(handler, getMessage(MSG_SYNC_USERINFO_SUCCESS, userinfo));
			}

			@Override
			protected void handeResponeFaild(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_SYNC_USERINFO_FAILD));
			}

		}, getErrorListener(handler));

		getHttpRequesttQueue().add(request);
	}

	/**
	 * 保存用户信息并上传服务器
	 * 
	 * @param userinfo
	 */
	public void saveUserInfo(UserInfo userinfo) {
		saveUserInfo(userinfo, null);
	}

	/**
	 * 保存用户信息并上传服务器
	 * 
	 * @param userinfo
	 * @param handler
	 */
	public void saveUserInfo(final UserInfo userinfo, final Handler handler) {
		saveUserInfoLocal(userinfo);
		Log.i(TAG, "#saveUserInfo:" + userinfo.getId());
		Map<String, String> params = new HashMap<String, String>();
		params.put("action", "save");
		params.put("uname", userinfo.getName());
		params.put("birthday", userinfo.getBirthday());
		params.put("sex", String.valueOf(userinfo.getSex()));
		params.put("description", userinfo.getDescription());
		params.put("email", userinfo.getEmail());
		params.put("place", userinfo.getCity());

		Request request = new JsonObjectRequest(URL_UPDATE_USER_INFO, params, new ResultResponeListener() {

			@Override
			protected void handeResponeSuccess(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_UPDATE_USERINFO_SUCCESS));
			}

			@Override
			protected void handeResponeFaild(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_UPDATE_USERINFO_FAILD));
			}
		}, getErrorListener(handler));

		getHttpRequesttQueue().add(request);
	}

	/**
	 * 持久化 用户信息到本地
	 * 
	 * @param userinfo
	 */
	private void saveUserInfoLocal(UserInfo userinfo) {
		Uri uri = Uri.withAppendedPath(Constant.CONTENT_URI_USERINFO_PROVIDER, userinfo.getId());
		Cursor cursor = getContentResolver().query(uri, null, null, null, null);
		if (cursor != null) {
			try {
				ContentValues values = new ContentValues();
				values.put(UserInfoColumns._ID, userinfo.getId());
				values.put(UserInfoColumns.NAME, userinfo.getName());
				values.put(UserInfoColumns.EMAIL, userinfo.getEmail());
				values.put(UserInfoColumns.PORTRAIT, userinfo.getProtrait());
				values.put(UserInfoColumns.BIRTHDAY, userinfo.getBirthday());
				values.put(UserInfoColumns.CITY, userinfo.getCity());
				values.put(UserInfoColumns.DESCRIPTION, userinfo.getDescription());
				values.put(UserInfoColumns.SEX, userinfo.getSex());
				values.put(UserInfoColumns.ISFRIEND, userinfo.getIsFriend());

				if (cursor.getCount() > 0) {
					getContentResolver().update(uri, values, null, null);
				} else {
					getContentResolver().insert(Constant.CONTENT_URI_USERINFO_PROVIDER, values);
				}

			} catch (Exception e) {
				Log.e(TAG, "persistentUserInfo", e);
			} finally {
				cursor.close();
			}

		}
		// 启动保存信息到服务器
	}

	/**
	 * 获取userinfo实体
	 * 
	 * @param cursor
	 * @return
	 */
	public UserInfo getUserInfoEntry(Cursor cursor) {
		UserInfo userInfo = new UserInfo();
		userInfo.setId(cursor.getString(cursor.getColumnIndex(UserInfoColumns._ID)));
		userInfo.setEmail(cursor.getString(cursor.getColumnIndex(UserInfoColumns.EMAIL)));
		userInfo.setName(cursor.getString(cursor.getColumnIndex(UserInfoColumns.NAME)));
		userInfo.setProtrait(cursor.getString(cursor.getColumnIndex(UserInfoColumns.PORTRAIT)));
		userInfo.setBirthday(cursor.getString(cursor.getColumnIndex(UserInfoColumns.BIRTHDAY)));
		userInfo.setCity(cursor.getString(cursor.getColumnIndex(UserInfoColumns.CITY)));
		userInfo.setDescription(cursor.getString(cursor.getColumnIndex(UserInfoColumns.DESCRIPTION)));
		userInfo.setSex(cursor.getInt(cursor.getColumnIndex(UserInfoColumns.SEX)));
		userInfo.setIsFriend(cursor.getInt(cursor.getColumnIndex(UserInfoColumns.ISFRIEND)));
		return userInfo;
	}

	/**
	 * 获取 地区实体
	 * 
	 * @param cursor
	 * @return
	 */
	public Place getPlaceEntry(Cursor cursor) {
		Place place = new Place();
		place.setId(cursor.getInt(cursor.getColumnIndex(PlaceColumns._ID)));
		place.setReid(cursor.getInt(cursor.getColumnIndex(PlaceColumns.REID)));
		place.setName(cursor.getString(cursor.getColumnIndex(PlaceColumns.NAME)));
		place.setDisOrder(cursor.getInt(cursor.getColumnIndex(PlaceColumns.DISORDER)));
		return place;
	}

	/**
	 * 根据用户id获取实体
	 * 
	 * @param userid
	 * @return
	 */
	public UserInfo getUserInfo(String userid) {
		Uri uri = Uri.withAppendedPath(Constant.CONTENT_URI_USERINFO_PROVIDER, userid);
		Cursor cursor = getContentResolver().query(uri, null, null, null, null);
		UserInfo userInfo = null;
		if (cursor != null) {
			try {
				if (cursor.moveToFirst()) {
					userInfo = getUserInfoEntry(cursor);
				}
			} catch (Exception e) {
				// TODO: handle exception
			} finally {
				cursor.close();
			}
		}
		return userInfo;
	}

	/**
	 * 查询地区
	 * 
	 * @param id
	 * @return
	 */
	public Place getPlace(int id) {
		Uri uri = Uri.withAppendedPath(Constant.CONTENT_URI_PLACE_PROVIDER, String.valueOf(id));
		Cursor cursor = getContentResolver().query(uri, null, null, null, null);
		Place place = new Place();
		if (cursor != null) {
			try {
				if (cursor.moveToFirst()) {
					place = getPlaceEntry(cursor);
				}
			} catch (Exception e) {
			} finally {
				cursor.close();
			}
		}
		return place;
	};

	/**
	 * 根据地区id获取名称
	 * 
	 * @param id
	 * @return
	 */
	public String loadPlaceName(String id) {
		String name = null;
		try {
			// 尝试转换成int
			Integer.valueOf(id);
		} catch (Exception e) {
			return name;
		}
		Uri uri = Uri.withAppendedPath(Constant.CONTENT_URI_PLACE_PROVIDER, id);
		Cursor cursor = getContentResolver().query(uri, null, null, null, null);
		if (cursor != null) {
			try {
				if (cursor.moveToFirst()) {
					name = cursor.getString(cursor.getColumnIndex(PlaceColumns.NAME));
				}
			} catch (Exception e) {
				Log.e(TAG, "loadPlaceName", e);
			} finally {
				cursor.close();
			}
		}
		return name;
	}

	/**
	 * 上传头像 还没实现
	 * 
	 * @param avatarBitmap
	 * @param handler
	 */
	@Deprecated
	public void uploadAvatar(Bitmap avatarBitmap, final Handler handler) {
		Log.e(TAG, "uoloadAvatar(Bitmap avatarBitmap,final Handler handler)  is not implement");
	}

	/**
	 * 上传头像
	 *
	 * @param avatar
	 * @param handler
	 */
	public void uploadAvatar(File avatar, final Handler handler) {
		
		//检查是否登录
		if(!checkLogin(handler)){
			return;
		}
		
		final String userid = getCurrentLoginUser().getUserId();

		Map<String, File> files = new HashMap<String, File>();
		Map<String, String> params = new HashMap<String, String>();
		files.put("face", avatar);
		params.put("action", "save");
		params.put("userid", userid);

		FileUploader.getInstance(mContext).upload(URL_UPLOAD_USER_AVATAR, files, params, new ResultResponeListener() {

			@Override
			protected void handeResponeSuccess(Respone result) {
				Message msg = getMessage(MSG_UPLOAD_USER_AVATR_SUCCESS);
				String avatarPath = null;
				try {
					avatarPath = result.getData().getString("avatar");
				} catch (JSONException e) {
					Log.e(TAG, "uploadAvatar error", e);
					msg.what = MSG_UPLOAD_USER_AVATR_FAILD;
					sendHandlerMessage(handler, msg);
					return;
				}

				// 更新数据数据
				UserInfo userInfo = getUserInfo(userid);
				userInfo.setProtrait(avatarPath);
				saveUserInfoLocal(userInfo);

				// 更新正在登陆的用户数据
				LoginUserInfo loginUserInfo = getCurrentLoginUser();
				if (loginUserInfo == null || loginUserInfo.getUserId() != userid) {
					msg.what = MSG_UPLOAD_USER_AVATR_FAILD;
					msg.getData().putString(MESSAGE_FALG, mContext.getString(R.string.login_not_logined));
					sendHandlerMessage(handler, msg);
					return;
				}
				loginUserInfo.setUserInfo(userInfo);

				sendHandlerMessage(handler, msg);
			}

			@Override
			protected void handeResponeFaild(Respone result) {
				Message msg = handler.obtainMessage(MSG_UPLOAD_USER_AVATR_FAILD);
				msg.getData().putString(MESSAGE_FALG, result.message);
				handler.sendMessage(msg);
			}
		}, getErrorListener(handler), Constant.HTTP_CONTENTTYPE_IMAGE_JPEG);
	}

	/**
	 * 添加新朋友
	 * 
	 * @param userid
	 * @param handler
	 */
	public void addNewfriend(final String userid, final Handler handler) {
		Log.i(TAG, "#addNewfriend:" + userid);
		
		//检查登录
		if(!checkLogin(handler)){
			return;
		}
		
		Map<String, String> params = new HashMap<String, String>();
		params.put("action", "newfriend");
		params.put("userid", userid);

		Request request = new JsonObjectRequest(URL_FRIEND, params, new ResultResponeListener() {

			@Override
			protected void handeResponeSuccess(Respone result) {
				Message msg = getMessage(MSG_NEW_FRIEND_SUCCESS);
				// 更新用户状态
				UserInfo userInfo = getUserInfo(userid);
				if (userInfo != null) {
					userInfo.setIsFriend(1);
					saveUserInfo(userInfo);
				}
				sendHandlerMessage(handler, msg);
			}

			@Override
			protected void handeResponeFaild(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_NEW_FRIEND_FAILD));
			}

		}, getErrorListener(handler));

		getHttpRequesttQueue().add(request);
	}

	/**
	 * 删除好友
	 * @param userid
	 * @param handler
	 */
	public void delFriend(final String userid,final Handler handler){
		//检查登录
		if(!checkLogin(handler)){
			return;
		}
		
		Map<String, String> params = new HashMap<String, String>();
		params.put("action", "delfriend");
		params.put("userid", userid);

		Request request = new JsonObjectRequest(URL_FRIEND, params, new ResultResponeListener() {

			@Override
			protected void handeResponeSuccess(Respone result) {
				Message msg = getMessage(MSG_DEL_FRIEND_SUCCESS);
				// 更新用户状态
				UserInfo userInfo = getUserInfo(userid);
				if (userInfo != null) {
					userInfo.setIsFriend(0);
					saveUserInfo(userInfo);
				}
				sendHandlerMessage(handler, msg);
			}

			@Override
			protected void handeResponeFaild(Respone result) {
				sendHandlerMessage(handler, getMessage(MSG_DEL_FRIEND_FAILD));
			}

		}, getErrorListener(handler));

		getHttpRequesttQueue().add(request);
	}
	/**
	 * 查询服务器上 未关注的会员
	 * 
	 * </br>注意这个只能在主线程调用
	 * 
	 * @param username
	 * @param handler
	 */
	public void serachUnfriend(final String username, final Handler handler) {
		Map<String, String> params = new HashMap<String, String>();
		params.put("action", "listunfriend");
		params.put("uname", username);
		// 由于 listFirends封装了查询服务器上朋友列表 和非朋友列表的接口，所以这里 做个message转发
		listFriends(params, new Handler(new Handler.Callback() {

			@Override
			public boolean handleMessage(Message msg) {
				Message handleMessage = new Message();
				handleMessage.obj = msg.obj;
				handleMessage.setData(msg.getData());
				switch (msg.what) {
				case MSG_SYNC_FRIEND_SUCCESS:
					handleMessage.what = MSG_QUERY_UNFRIEND_SUCCESS;
					break;
				default:
					// 其他情况都为 失败
					handleMessage.what = MSG_QUERY_UNFRIEND_FAILD;
					break;
				}
				if (handler != null) {
					handler.sendMessage(handleMessage);
				}
				return true;
			}
		}));
	}

	/**
	 * 同步好友信息
	 * 
	 * @param handler
	 */
	public void syncFrieds(final Handler handler) {
		Map<String, String> params = new HashMap<String, String>();
		params.put("action", "listfriend");
		listFriends(params, handler);
	}

	/**
	 * 查询服务器好友
	 * 
	 * @param params
	 *            http请求参数
	 * @param handler
	 */
	public void listFriends(Map<String, String> params, final Handler handler) {
		//不检查登录

		Request request = new JsonArrayRequest(URL_FRIEND, params, new Listener<JSONArray>() {

			@Override
			public void onResponse(JSONArray json) {

				// 这里比较耗时 放入到 aysnctask中执行
				AsyncTask handleTask = new AsyncTask<JSONArray, Integer, android.os.Message>() {

					@Override
					protected android.os.Message doInBackground(JSONArray... params) {
						android.os.Message handlerMsg = null;
						try {
							JSONArray jsonarray = params[0];
							List<UserInfo> users = HttpHelper.getJsonArray(jsonarray, new TypeToken<List<UserInfo>>() {
							});
							// 这改成批量修改？提高性能,或者不需要保存？
							for (UserInfo user : users) {
								saveUserInfo(user);
							}
							if(handler != null){
								handlerMsg = new Message();
								handlerMsg.what = MSG_SYNC_FRIEND_SUCCESS;
								handlerMsg.obj = users;
							}
						} catch (Exception e) {
							Log.e(TAG, "syncFriends error", e);
							if(handler != null){
								handlerMsg = new Message();
								handlerMsg.what = MSG_SYNC_FRIEND_FAILD;
							}
						}
						return handlerMsg;
					}

					@Override
					protected void onPostExecute(android.os.Message result) {
						if(handler != null){
							handler.sendMessage(result);
						}
						super.onPostExecute(result);
					}
				};

				handleTask.execute(new JSONArray[] { json });
			}

		}, getErrorListener(handler));

		getHttpRequesttQueue().add(request);
	}
	
	/**
	 * 把本地所有userinfo 的isfriend设置成false，一般用在注销时，防止再好友列表中出现
	 */
	public void clearFreindRelationship(){
		ContentValues values = new ContentValues();
		values.put(UserInfoColumns.ISFRIEND, 0);
		getContentResolver().update(Constant.CONTENT_URI_USERINFO_PROVIDER, values, null, null);
	}
} public class BaseServiceHandler<T> extends Handler {
	protected Callback mCallback;

	/**
	 * 获取 完成以后 msg.obj
	 * 
	 * @param message
	 * @return
	 */
	T getMessageEntry(Message message) {
		if (message.obj != null) {
			return (T) message.obj;
		}
		return null;
	}

	/**
	 * 获取服务器消息
	 * 
	 * @param message
	 * @return
	 */
	String getServerMessage(Message message) {
		return message.getData().getString(BaseService.MESSAGE_FALG);
	}

	/**
	 * 调用callback
	 * 
	 * @param msg
	 * @param isSuccess
	 */
	protected void callCallback(Message msg, boolean isSuccess) {
		if (mCallback != null) {
			// 使用msg.obj 来传输用户列表
			mCallback.complate(isSuccess, getMessageEntry(msg), getServerMessage(msg));
		}
	}

	/**
	 * 同步用户信息 Callback
	 * 
	 * @author chenzipeng
	 *
	 */
	public interface Callback<T> {
		/**
		 * 当完成以后的回调
		 * 
		 * @param succes
		 *            结果
		 * @param entry
		 *            数据实体 T
		 * @param message
		 *            服务器返回的消息
		 */
		public void complate(boolean success, T entry, String message);
	}
} public class MessageQueryHandler extends BaseServiceHandler<Cursor> {

	/**
	 * 
	 * @param callback
	 *            Cursor类型，代表 message 所在的游标
	 */
	public MessageQueryHandler(Callback<Cursor> callback) {
		super();
		mCallback = callback;
	}

	@Override
	public void handleMessage(Message msg) {
		switch (msg.what) {
		case MessageService.MSG_QUERY_MESSAGE_SUCCESS:
			callCallback(msg, true);
			break;
		default:
			callCallback(msg, false);
			break;
		}

		super.handleMessage(msg);
	}

} public class MessageSendHandler extends BaseServiceHandler {

	public MessageSendHandler(Callback callback) {
		super();
		mCallback = callback;
	}

	@Override
	public void handleMessage(Message msg) {
		switch (msg.what) {
		case MessageService.MSG_SEND_MESSAGE_SUCCESS:
			callCallback(msg, true);
			break;
		default:
			callCallback(msg, false);
			break;
		}
		super.handleMessage(msg);
	}
} public class UserSyncHandler extends Handler {
	private String mUserid;
	private SyncCallback mSyncCallback;

	public UserSyncHandler(String userid, SyncCallback callback) {
		super();
		this.mUserid = userid;
		mSyncCallback = callback;
	}

	@Override
	public void handleMessage(Message msg) {
		switch (msg.what) {
		case UserService.MSG_SYNC_USERINFO_SUCCESS:
			if (mSyncCallback != null) {
				mSyncCallback.complate(true, UserService.getInstance().getUserInfo(mUserid));
			}
			break;
		default:
			if (mSyncCallback != null) {
				mSyncCallback.complate(false, null);
			}
			break;
		}
		super.handleMessage(msg);
	}

	/**
	 * 同步用户信息 Callback
	 * 
	 * @author chenzipeng
	 *
	 */
	public interface SyncCallback {
		/**
		 * 当完成以后的回调
		 * 
		 * @param succes
		 *            结果
		 * @param userInfo
		 *            如果success == false，这里就为null
		 */
		public void complate(boolean succes, UserInfo userInfo);
	}
} public class MessageItem extends LinearLayout implements View.OnClickListener {
	private CircularLoadImageView mHeaderView;
	private TextView mContentView;
	private ImageView mStateView;
	private ViewGroup mMessageContainer;

	private Message mMessage;
	private boolean mMyself;
	private UserHeaderLoader mUserHeaderLoader;
	private final int padding = 10;// dp

	public MessageItem(Context context) {
		super(context);

		LayoutParams layoutParams = new LayoutParams(android.view.ViewGroup.LayoutParams.MATCH_PARENT,
				android.view.ViewGroup.LayoutParams.WRAP_CONTENT);
		setLayoutParams(layoutParams);

		int paddingPx = DensityHelper.dip2px(context, padding);
		setPadding(paddingPx, paddingPx, paddingPx, paddingPx);

		inflate(context, R.layout.item_message, this);

		mHeaderView = (CircularLoadImageView) findViewById(R.id.message_header);
		mHeaderView.setOnClickListener(this);
		mContentView = (TextView) findViewById(R.id.message_content);
		mStateView = (ImageView) findViewById(R.id.message_state);
		mMessageContainer = (ViewGroup) findViewById(R.id.message_container);

	}

	@SuppressLint("NewApi")
	public void setMessage(Message message, final boolean myself) {
		mMessage = message;
		mMyself = myself;

		mContentView.setText(mMessage.getMessage());
		mUserHeaderLoader.load(mHeaderView, message.getFloginid());

		// 设置消息底图
		if (mMyself) {
			mMessageContainer.setBackgroundResource(R.drawable.message_item_right);
		} else {
			mMessageContainer.setBackgroundResource(R.drawable.message_item_left);
		}

		// 设置状态
		if (mMessage.getState() == Constant.MESSAGE_STATE_SENDING) {
			mStateView.setVisibility(View.VISIBLE);
			mStateView.setImageResource(R.drawable.loading);

		} else if (mMessage.getState() == Constant.MESSAGE_STATE_FAILD) {
			mStateView.setVisibility(View.VISIBLE);
			mStateView.setImageResource(R.drawable.warning);

		} else if (mMessage.getState() == Constant.MESSAGE_STATE_SENED) {
			mStateView.setVisibility(View.GONE);
		}
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		int childCount = getChildCount();
		int left = getPaddingLeft();
		int right = getMeasuredWidth() - getPaddingRight();
		int top = getPaddingTop();
		int bottom = getMeasuredHeight() - getPaddingBottom();

		for (int i = 0; i < childCount; i++) {
			View child = getChildAt(i);
			final int childWidth = child.getMeasuredWidth();

			final LayoutParams childLayoutParams = (LayoutParams) child.getLayoutParams();

			if (mMyself) {
				// 如果是自己，就从右到到左布局
				int childLeft = right - childWidth - childLayoutParams.rightMargin;
				int childright = childLeft + childWidth;
				right = childLeft;
				child.layout(childLeft, top, childright, bottom);
			} else {
				int childLeft = left + childLayoutParams.leftMargin;
				int childright = childLeft + childWidth;
				left = childright;
				child.layout(childLeft, top, childright, bottom);
			}
		}
	}

	public UserHeaderLoader getUserHeaderLoader() {
		return mUserHeaderLoader;
	}

	public void setUserHeaderLoader(UserHeaderLoader userHeaderLoader) {
		mUserHeaderLoader = userHeaderLoader;
	}

	/**
	 * 加载头像 loader
	 * 
	 * @author chenzipeng
	 *
	 */
	public interface UserHeaderLoader {
		public void load(CircularLoadImageView loadImageView, String userid);
	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.message_header:
			// 点击头像启动个人信息
			String userid = null;
			if (mMyself) {
				userid = mMessage.getFloginid();
			} else {
				userid = mMessage.getTologinid();
			}
			Intent intent = new Intent(v.getContext(), PersonalInfoActivity.class);
			intent.putExtra(PersonalInfoActivity.KEY_USERID, userid);
			v.getContext().startActivity(intent);
			break;

		default:
			break;
		}
	}

} public class Topbar extends RelativeLayout {

	private TextView mTitleView;
	private View mBackButton;
	private String mTitle;
	private boolean isShowBackButton;

	public Topbar(Context context, AttributeSet attrs) {
		super(context, attrs);

		// Styleables from XML
		TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.Topbar);

		if (a.hasValue(R.styleable.Topbar_title)) {
			mTitle = a.getString(R.styleable.Topbar_title);
		} else {
			mTitle = new String();
		}

		isShowBackButton = a.getBoolean(R.styleable.Topbar_showBackButton, true);
		((LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.topbar, this);

		mShowAnimator = AnimatorInflater.loadAnimator(getContext(), R.animator.topbar_show);
		mShowAnimator.setTarget(this);
		mShowAnimator.addListener(mShowAnimatorListener);

		mHideAnimator = AnimatorInflater.loadAnimator(getContext(), R.animator.topbar_hide);
		mHideAnimator.setTarget(this);
		mHideAnimator.addListener(mHideAnimatorListener);
	}

	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		mTitleView = (TextView) findViewById(R.id.topbar_title);
		setTitle(mTitle);

		mBackButton = findViewById(R.id.topbar_back);
		mBackButton.setOnClickListener(mBackListener);

		if (isShowBackButton) {
			showBackButton();
		} else {
			hideBackButton();
		}
	}

	/**
	 * 设置标题
	 * 
	 * @param title
	 */
	public void setTitle(CharSequence title) {
		mTitleView.setText(title);
	}

	/**
	 * 设置 返回动作，
	 * 
	 * @param runnable
	 */
	public void setBackAction(Runnable runnable) {
		mBackRunnable = runnable;
	}

	private OnClickListener mBackListener = new OnClickListener() {

		@Override
		public void onClick(View v) {
			if (mBackRunnable != null) {
				mBackRunnable.run();
			}
		}
	};

	/**
	 * 默认返回动作 会关闭当前activity
	 */
	private Runnable mBackRunnable = new Runnable() {

		@Override
		public void run() {
			// 默认是关闭当前activity
			if (getContext() instanceof Activity) {
				((Activity) getContext()).finish();
			}
		}
	};

	// 显示 隐藏动画
	private Animator mShowAnimator;
	private Animator mHideAnimator;

	private boolean isShowAnimRuning = false;
	private boolean isHideAnimRuning = false;

	private AnimatorListener mShowAnimatorListener = new AnimatorListener() {

		@Override
		public void onAnimationStart(Animator animation) {
			isShowAnimRuning = true;
			setVisibility(View.VISIBLE);
		}

		@Override
		public void onAnimationEnd(Animator animation) {
			isShowAnimRuning = false;
			setVisibility(View.VISIBLE);
		}

		@Override
		public void onAnimationCancel(Animator animation) {

		}

		@Override
		public void onAnimationRepeat(Animator animation) {

		}
	};

	private AnimatorListener mHideAnimatorListener = new AnimatorListener() {

		@Override
		public void onAnimationStart(Animator animation) {
			isHideAnimRuning = true;
			setVisibility(View.VISIBLE);
		}

		@Override
		public void onAnimationEnd(Animator animation) {
			isHideAnimRuning = false;
			setVisibility(View.GONE);
		}

		@Override
		public void onAnimationCancel(Animator animation) {

		}

		@Override
		public void onAnimationRepeat(Animator animation) {

		}
	};

	public void showAnimation() {
		if (isShowAnimRuning) {
			return;
		}
		if (isHideAnimRuning) {
			mHideAnimator.cancel();
			mShowAnimator.start();
			return;
		}

		if (this.getVisibility() == View.GONE) {
			mShowAnimator.start();
		}
	}

	public void hideAnimation() {
		if (isHideAnimRuning) {
			return;
		}
		if (isShowAnimRuning) {
			mShowAnimator.cancel();
		}
		if (this.getVisibility() == View.VISIBLE) {
			mHideAnimator.start();
		}
	}

	public void showBackButton() {
		mBackButton.setVisibility(View.VISIBLE);
	}

	public void hideBackButton() {
		mBackButton.setVisibility(View.GONE);
	}
} public class CircularLoadImageView extends LoadImageView {
	private int mBorderThickness = 1;
	private int defaultColor = 0xFFFFFFFF;
	// 如果只有其中一个有值，则只画一个圆形边框
	private int mBorderOutsideColor = Color.WHITE;
	private int mBorderInsideColor = Color.GRAY;
	// 控件默认长、宽
	private int defaultWidth = 0;
	private int defaultHeight = 0;

	public CircularLoadImageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// Styleables from XML
		TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CircularLoadImageView);

		if (a.hasValue(R.styleable.CircularLoadImageView_defaultSrc)) {
			mDefaultImageId = a.getResourceId(R.styleable.CircularLoadImageView_defaultSrc, mDefaultImageId);
		}
	}

	@Override
	protected void onDraw(Canvas canvas) {
		Drawable drawable = getDrawable();
		if (drawable == null) {
			return;
		}
		if (getWidth() == 0 || getHeight() == 0) {
			return;
		}

		if (drawable.getClass() == NinePatchDrawable.class)
			return;
		if (!(drawable instanceof BitmapDrawable))
			return;
		Bitmap b = ((BitmapDrawable) drawable).getBitmap();
		Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);
		if (defaultWidth == 0) {
			defaultWidth = getWidth();
		}

		if (defaultHeight == 0) {
			defaultHeight = getHeight();
		}

		int radius = 0;

		if (mBorderInsideColor != defaultColor && mBorderOutsideColor != defaultColor) {// 定义画两个边框，分别为外圆边框和内圆边框

			radius = (defaultWidth < defaultHeight ? defaultWidth : defaultHeight) / 2 - 2 * mBorderThickness;
			// 画内圆
			drawCircleBorder(canvas, radius + mBorderThickness / 2, mBorderInsideColor);
			// 画外圆
			drawCircleBorder(canvas, radius + mBorderThickness + mBorderThickness / 2, mBorderOutsideColor);

		} else if (mBorderInsideColor != defaultColor && mBorderOutsideColor == defaultColor) {// 定义画一个边框
			radius = (defaultWidth < defaultHeight ? defaultWidth : defaultHeight) / 2 - mBorderThickness;
			drawCircleBorder(canvas, radius + mBorderThickness / 2, mBorderInsideColor);

		} else if (mBorderInsideColor == defaultColor && mBorderOutsideColor != defaultColor) {// 定义画一个边框
			radius = (defaultWidth < defaultHeight ? defaultWidth : defaultHeight) / 2 - mBorderThickness;
			drawCircleBorder(canvas, radius + mBorderThickness / 2, mBorderOutsideColor);

		} else {// 没有边框
			radius = (defaultWidth < defaultHeight ? defaultWidth : defaultHeight) / 2;
		}

		Bitmap roundBitmap = getCroppedRoundBitmap(bitmap, radius);
		canvas.drawBitmap(roundBitmap, defaultWidth / 2 - radius, defaultHeight / 2 - radius, null);
	}

	/**
	 * 
	 * 获取裁剪后的圆形图片
	 * 
	 * @param radius半径
	 */

	public Bitmap getCroppedRoundBitmap(Bitmap bmp, int radius) {
		Bitmap scaledSrcBmp;
		int diameter = radius * 2;
		// 为了防止宽高不相等，造成圆形图片变形，因此截取长方形中处于中间位置最大的正方形图片
		int bmpWidth = bmp.getWidth();
		int bmpHeight = bmp.getHeight();
		int squareWidth = 0, squareHeight = 0;
		int x = 0, y = 0;
		Bitmap squareBitmap;
		if (bmpHeight > bmpWidth) {// 高大于宽
			squareWidth = squareHeight = bmpWidth;
			x = 0;
			y = (bmpHeight - bmpWidth) / 2;
			// 截取正方形图片
			squareBitmap = Bitmap.createBitmap(bmp, x, y, squareWidth, squareHeight);
		} else if (bmpHeight < bmpWidth) {// 宽大于高
			squareWidth = squareHeight = bmpHeight;
			x = (bmpWidth - bmpHeight) / 2;
			y = 0;
			squareBitmap = Bitmap.createBitmap(bmp, x, y, squareWidth, squareHeight);
		} else {
			squareBitmap = bmp;
		}

		if (squareBitmap.getWidth() != diameter || squareBitmap.getHeight() != diameter) {
			scaledSrcBmp = Bitmap.createScaledBitmap(squareBitmap, diameter, diameter, true);
		} else {
			scaledSrcBmp = squareBitmap;
		}

		Bitmap output = Bitmap.createBitmap(scaledSrcBmp.getWidth(), scaledSrcBmp.getHeight(), Config.ARGB_8888);
		Canvas canvas = new Canvas(output);
		Paint paint = new Paint();
		Rect rect = new Rect(0, 0, scaledSrcBmp.getWidth(), scaledSrcBmp.getHeight());
		paint.setAntiAlias(true);
		paint.setFilterBitmap(true);
		paint.setDither(true);
		canvas.drawARGB(0, 0, 0, 0);
		canvas.drawCircle(scaledSrcBmp.getWidth() / 2, scaledSrcBmp.getHeight() / 2, scaledSrcBmp.getWidth() / 2, paint);
		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(scaledSrcBmp, rect, rect, paint);

		bmp = null;
		squareBitmap = null;
		scaledSrcBmp = null;
		return output;

	}

	/**
	 * 
	 * 边缘画圆
	 */
	private void drawCircleBorder(Canvas canvas, int radius, int color) {
		Paint paint = new Paint();
		/* 去锯齿 */
		paint.setAntiAlias(true);
		paint.setFilterBitmap(true);
		paint.setDither(true);
		paint.setColor(color);
		/* 设置paint的　style　为STROKE：空心 */
		paint.setStyle(Paint.Style.STROKE);
		/* 设置paint的外框宽度 */
		paint.setStrokeWidth(mBorderThickness);
		canvas.drawCircle(defaultWidth / 2, defaultHeight / 2, radius, paint);
	}

} public class PullRefreshGridLayout extends PullToRefreshGridView {

	private UpdateDataExecutable mUpdateDataExecutable;

	protected TextView mMsgTextView;
	protected AnimatorSet mShowMsgAnimatorSet;

	public PullRefreshGridLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		// 允许刷新的时候滑动
		setScrollingWhileRefreshingEnabled(true);
	}

	private OnRefreshListener2<GridView> mOnRefreeListener = new OnRefreshListener2<GridView>() {

		@Override
		public void onPullDownToRefresh(PullToRefreshBase<GridView> refreshView) {
			updateData(true);
		}

		@Override
		public void onPullUpToRefresh(PullToRefreshBase<GridView> refreshView) {

			// refresh的监听需要忽略 mode设置为disabled的情况， 比如题型选择那里。
			if (getMode() == Mode.DISABLED) {
				return;
			}

			if (!isLoadEnd()) {
				updateData(false);
			}
		}
	};

	private OnLastItemVisibleListener mOnLastItemVisibleListener = new OnLastItemVisibleListener() {
		private final int DEAFLUT_VISIBLE_ITEM_INDEX = -1;
		private int lastVisibleItemIndex = DEAFLUT_VISIBLE_ITEM_INDEX;

		@Override
		public void onLastItemVisible() {
			if (getMode() == Mode.BOTH || getMode() == Mode.PULL_UP_TO_REFRESH) {
				int tempLastVisibleItemIndex = PullRefreshGridLayout.this.getRefreshableView().getLastVisiblePosition();
				if (!isLoadEnd() && lastVisibleItemIndex != tempLastVisibleItemIndex) {
					lastVisibleItemIndex = tempLastVisibleItemIndex;
					setCurrentMode(Mode.PULL_FROM_END);// 强制设置下拉
					setState(State.REFRESHING, false);
				}
			}
		}
	};

	@Override
	protected void onFinishInflate() {
		super.onFinishInflate();
		setMode(Mode.BOTH);
		setOnRefreshListener(mOnRefreeListener);
		setOnLastItemVisibleListener(mOnLastItemVisibleListener);
		// TODO 自定义刷新header & footer
		// setLoadingDrawable(drawable)

	};

	/**
	 * 强制上拉更新
	 */
	public void refresh() {
		setState(State.MANUAL_REFRESHING, false);
	}

	/**
	 * 调用更新数据
	 * 
	 * @param pullDownToRefresh
	 *            是否下拉更新， true ： 下拉更新</br> false: 上拉更新
	 */
	protected void updateData(boolean pullDownToRefresh) {

		if (getUpdateDataExecutable() != null) {
			getUpdateDataExecutable().update(this, pullDownToRefresh);
		}
	}

	/**
	 * 数据更新接口
	 * 
	 * @author chenzipeng
	 * 
	 */
	public interface UpdateDataExecutable {
		/**
		 * 更新数据 在数据更新完成以后调用 PullRefreshGridLayout.onRefreshComplete();来控制完成
		 * 
		 * @param view
		 *            PullRefireshLayout
		 * @param pullDownToRefresh
		 *            是否下拉更新， true ： 下拉更新</br> false: 上拉更新
		 */
		void update(PullRefreshGridLayout view, boolean pullDownToRefresh);
	}

	/**
	 * 更新数据用adapter接口
	 * 
	 * @author chenzipeng
	 *
	 */
	public interface UpdateDataAdapter {
		/**
		 * 返回最后一个id
		 * 
		 * @return
		 */
		long getLastItemId();
	}

	public void setUpdateDataExecutable(UpdateDataExecutable updateDataExecutable) {
		mUpdateDataExecutable = updateDataExecutable;
	}

	public UpdateDataExecutable getUpdateDataExecutable() {
		return mUpdateDataExecutable;
	}

	/**
	 * 显示运行结果弹出
	 * 
	 * @param msg
	 */
	public void showRefreshResult(String msg) {
		mMsgTextView.setText(msg);
		mShowMsgAnimatorSet.start();
	}

	private ArrayList<FixedViewInfo> mHeaderViewInfos = new ArrayList<FixedViewInfo>();
	private ArrayList<FixedViewInfo> mFooterViewInfos = new ArrayList<FixedViewInfo>();

	/**
	 * Add a fixed view to appear at the top of the list. If this method is
	 * called more than once, the views will appear in the order they were
	 * added. Views added using this call can take focus if they want.
	 * <p>
	 * Note: When first introduced, this method could only be called before
	 * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
	 * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be called
	 * at any time. If the ListView's adapter does not extend
	 * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
	 * instance of {@link WrapperListAdapter}.
	 *
	 * @param v
	 *            The view to add.
	 */
	public void addHeaderView(View v) {
		final FixedViewInfo info = new FixedViewInfo();
		info.view = v;
		info.data = null;
		info.isSelectable = false;
		mHeaderViewInfos.add(info);
		addSpecialView();
	}

	/**
	 * Add a fixed view to appear at the top of the list. If this method is
	 * called more than once, the views will appear in the order they were
	 * added. Views added using this call can take focus if they want.
	 * <p>
	 * Note: When first introduced, this method could only be called before
	 * setting the adapter with {@link #setAdapter(ListAdapter)}. Starting with
	 * {@link android.os.Build.VERSION_CODES#KITKAT}, this method may be called
	 * at any time. If the ListView's adapter does not extend
	 * {@link HeaderViewListAdapter}, it will be wrapped with a supporting
	 * instance of {@link WrapperListAdapter}.
	 *
	 * @param v
	 *            The view to add.
	 */
	public void addFooterView(View v) {
		final FixedViewInfo info = new FixedViewInfo();
		info.view = v;
		info.data = null;
		info.isSelectable = false;
		mFooterViewInfos.add(info);
		addSpecialView();
	}

	private void addSpecialView() {
		if (getRefreshableView() != null) {
			// Wrap the adapter if it wasn't already wrapped.
			ListAdapter adapter = getRefreshableView().getAdapter();
			if (adapter != null) {
				if (!(adapter instanceof HeaderViewListAdapter)) {
					adapter = new HeaderViewListAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);
					this.setAdapter(adapter);
				}

				// In the case of re-adding a header view, or adding one later
				// on,
				// we need to notify the observer.
				if (adapter instanceof BaseAdapter) {
					((BaseAdapter) adapter).notifyDataSetChanged();
				} else {
					Log.w("pullrefrshGirdlayout", " addHeaderView not notifyDataSetChanged");
				}

			}
		}
	}
} public interface UpdateDataExecutable {
	/**
	 * 更新数据 在数据更新完成以后调用 PullRefreshGridLayout.onRefreshComplete();来控制完成
	 * 
	 * @param view
	 *            PullRefireshLayout
	 * @param pullDownToRefresh
	 *            是否下拉更新， true ： 下拉更新</br> false: 上拉更新
	 */
	void update(PullRefreshGridLayout view, boolean pullDownToRefresh);
}
import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.lingganhezi.myapp.R;
import com.lingganhezi.myapp.entity.LoginUserInfo;
import com.lingganhezi.myapp.entity.Message;
import com.lingganhezi.myapp.entity.MessageSession;
import com.lingganhezi.myapp.entity.UserInfo;
import com.lingganhezi.myapp.service.LoginService;
import com.lingganhezi.myapp.service.MessageService;
import com.lingganhezi.myapp.service.UserService;
import com.lingganhezi.myapp.service.handler.BaseServiceHandler;
import com.lingganhezi.myapp.service.handler.MessageQueryHandler;
import com.lingganhezi.myapp.service.handler.MessageSendHandler;
import com.lingganhezi.myapp.service.handler.UserSyncHandler;
import com.lingganhezi.myapp.ui.MessageItem;
import com.lingganhezi.myapp.ui.Topbar;
import com.lingganhezi.ui.widget.CircularLoadImageView;
import com.lingganhezi.ui.widget.PullRefreshGridLayout;
import com.lingganhezi.ui.widget.PullRefreshGridLayout.UpdateDataExecutable;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
package com.lingganhezi.myapp.ui.activity;



public class MessageActivity extends BaseActivity implements View.OnClickListener {
	private MessageService mMessageService;

	private PullRefreshGridLayout mMessageList;
	private MessageAdapter mMessageAdapter;
	private View mSendButton;
	private View mShowEmoButton;// TODO 实现表情
	private EditText mMessageText;
	private Topbar mTopbar;

	private MessageSession mSession;

	public final static String KEY_MESSAGE_SESSION_ID = "KEY_MESSAGE_SESSION_ID";

	@Override
	protected void onCreate(Bundle arg0) {
		super.onCreate(arg0);
		setContentView(R.layout.activity_message);

		mMessageAdapter = new MessageAdapter(this);

		mMessageList = (PullRefreshGridLayout) findViewById(R.id.messages_list);
		mTopbar = (Topbar) findViewById(R.id.topbar);
		mSendButton = findViewById(R.id.message_send);
		// mShowEmoButton = findViewById(R.id.message_show_emo_btn);
		mMessageText = (EditText) findViewById(R.id.message_text);

		mMessageList.setAdapter(mMessageAdapter);
		mMessageList.setUpdateDataExecutable(mMessageUpdater);
		// 设置只允许下拉更新
		mMessageList.setMode(Mode.PULL_FROM_START);

		mSendButton.setOnClickListener(this);
		// mShowEmoButton.setOnClickListener(this);

		mMessageService = MessageService.getInstance();

		init(getIntent());

	}

	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.message_send:
			sendMessage();
			break;
		default:
			break;
		}
	}

	@Override
	protected void onNewIntent(Intent intent) {
		super.onNewIntent(intent);
		init(intent);
	}

	private void init(Intent intent) {
		if (!intent.hasExtra(KEY_MESSAGE_SESSION_ID)) {
			finish();
			return;
		}

		if (!LoginService.getInstance().isLogined()) {
			showToast(R.string.dialog_login_not_logined);
			finish();
			return;
		}

		int sessionid = intent.getIntExtra(KEY_MESSAGE_SESSION_ID, -1);

		MessageSession session = mMessageService.getMessageSession(sessionid);
		if (session == null) {
			showToast(R.string.message_session_not_found);
			finish();
			return;
		}
		// 获取对方的id
		mSession = session;

		initTargetUserInfo();

		// 开始初始化Message
		Bundle params = new Bundle();
		params.putInt(KEY_MESSAGE_SESSION_ID, sessionid);
		getSupportLoaderManager().initLoader(R.id.messages_list, params, mMessageLoaderCallback);
	}

	private LoaderCallbacks<Cursor> mMessageLoaderCallback = new LoaderCallbacks<Cursor>() {

		@Override
		public void onLoaderReset(Loader<Cursor> loader) {
			mMessageAdapter.changeCursor(null);
		}

		@Override
		public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
			mMessageAdapter.changeCursor(cursor);
			// 设置到最后
			int count = mMessageList.getRefreshableView().getCount();
			int pos = count - 1;
			mMessageList.getRefreshableView().setSelection(pos);

		}

		@Override
		public Loader<Cursor> onCreateLoader(int loaderid, Bundle params) {
			int sessionid = params.getInt(KEY_MESSAGE_SESSION_ID);
			return mMessageService.getMessageLoader(sessionid);
		}
	};

	private class MessageAdapter extends CursorAdapter {
		private MessageService mMessageService;
		private UserService mUserService;

		public MessageAdapter(Context context) {
			super(context, null, true);
			mMessageService = MessageService.getInstance();
			mUserService = UserService.getInstance();
		}

		@Override
		public void bindView(View messageView, Context context, Cursor cursor) {
			LoginUserInfo currentUser = mUserService.getCurrentLoginUser();
			Message message = mMessageService.getMessageEntry(cursor);
			boolean myself = (message.getFloginid().equals(currentUser.getUserId()));
			((MessageItem) messageView).setMessage(message, myself);
		}

		@Override
		public View newView(Context context, Cursor c, ViewGroup parent) {
			MessageItem item = new MessageItem(context);
			item.setUserHeaderLoader(mMessageUserHeaderLoader);
			return item;
		}

		private MessageItem.UserHeaderLoader mMessageUserHeaderLoader = new MessageItem.UserHeaderLoader() {

			@Override
			public void load(final CircularLoadImageView loadImageView, final String userid) {
				UserInfo user = mUserService.getUserInfo(userid);
				if (user != null) {
					loadImageView.setImageUrl(user.getProtrait(), getImageLoder());
				}
			}

		};
	}

	private UpdateDataExecutable mMessageUpdater = new UpdateDataExecutable() {