/**
   * 服务端主动发送已读通知
   *
   * @param readNotify
   */
  public void onNotifyRead(IMMessage.IMMsgDataReadNotify readNotify) {
    logger.d("chat#onNotifyRead");
    // 发送此信令的用户id
    int trigerId = readNotify.getUserId();
    int loginId = IMLoginManager.instance().getLoginId();
    if (trigerId != loginId) {
      logger.i("onNotifyRead# trigerId:%s,loginId:%s not Equal", trigerId, loginId);
      return;
    }
    // 现在的逻辑是msgId之后的 全部都是已读的
    // 不做复杂判断了,简单处理
    int msgId = readNotify.getMsgId();
    int peerId = readNotify.getSessionId();
    int sessionType = ProtoBuf2JavaBean.getJavaSessionType(readNotify.getSessionType());
    String sessionKey = EntityChangeEngine.getSessionKey(peerId, sessionType);

    // 通知栏也要去除掉
    NotificationManager notifyMgr =
        (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
    if (notifyMgr == null) {
      return;
    }
    int notificationId = IMNotificationManager.instance().getSessionNotificationId(sessionKey);
    notifyMgr.cancel(notificationId);

    UnreadEntity unreadSession = findUnread(sessionKey);
    if (unreadSession != null && unreadSession.getLaststMsgId() <= msgId) {
      // 清空会话session
      logger.d("chat#onNotifyRead# unreadSession onLoginOut");
      readUnreadSession(sessionKey);
    }
  }
Пример #2
0
  public void onRepNormalGroupList(IMGroup.IMNormalGroupListRsp normalGroupListRsp) {
    logger.i("group#onRepNormalGroupList");
    int groupSize = normalGroupListRsp.getGroupVersionListCount();
    logger.i("group#onRepNormalGroupList cnt:%d", groupSize);
    List<IMBaseDefine.GroupVersionInfo> versionInfoList =
        normalGroupListRsp.getGroupVersionListList();

    /** 对比DB中的version字段 */
    // 这块对比的可以抽离出来
    List<IMBaseDefine.GroupVersionInfo> needInfoList = new ArrayList<>();

    for (IMBaseDefine.GroupVersionInfo groupVersionInfo : versionInfoList) {
      int groupId = groupVersionInfo.getGroupId();
      int version = groupVersionInfo.getVersion();
      if (groupMap.containsKey(groupId) && groupMap.get(groupId).getVersion() == version) {
        continue;
      }
      IMBaseDefine.GroupVersionInfo versionInfo =
          IMBaseDefine.GroupVersionInfo.newBuilder().setVersion(0).setGroupId(groupId).build();
      needInfoList.add(versionInfo);
    }

    // 事件触发的时候需要注意 todo
    if (needInfoList.size() > 0) {
      reqGetGroupDetailInfo(needInfoList);
    }
  }
Пример #3
0
 /** 联系人页面正式群的请求 todo 正式群与临时群逻辑上的分开的,但是底层应该是想通的 */
 private void reqGetNormalGroupList() {
   logger.i("group#reqGetNormalGroupList");
   int loginId = imLoginManager.getLoginId();
   IMGroup.IMNormalGroupListReq normalGroupListReq =
       IMGroup.IMNormalGroupListReq.newBuilder().setUserId(loginId).build();
   int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
   int cid = IMBaseDefine.GroupCmdID.CID_GROUP_NORMAL_LIST_REQUEST_VALUE;
   imSocketManager.sendRequest(normalGroupListReq, sid, cid);
   logger.i("group#send packet to server");
 }
 public UnreadEntity findUnread(String sessionKey) {
   logger.d("unread#findUnread# buddyId:%s", sessionKey);
   if (TextUtils.isEmpty(sessionKey) || unreadMsgMap.size() <= 0) {
     logger.i("unread#findUnread# no unread info");
     return null;
   }
   if (unreadMsgMap.containsKey(sessionKey)) {
     return unreadMsgMap.get(sessionKey);
   }
   return null;
 }
  private void showInNotificationBar(
      String title, String ticker, Bitmap iconBitmap, int notificationId, Intent intent) {
    logger.d("notification#showInNotificationBar title:%s ticker:%s", title, ticker);

    NotificationManager notifyMgr =
        (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
    if (notifyMgr == null) {
      return;
    }

    Builder builder = new NotificationCompat.Builder(ctx);
    builder.setContentTitle(title);
    builder.setContentText(ticker);
    builder.setSmallIcon(R.drawable.tt_small_icon);
    builder.setTicker(ticker);
    builder.setWhen(System.currentTimeMillis());
    builder.setAutoCancel(true);

    // this is the content near the right bottom side
    // builder.setContentInfo("content info");

    if (configurationSp.getCfg(
        SysConstant.SETTING_GLOBAL, ConfigurationSp.CfgDimension.VIBRATION)) {
      // delay 0ms, vibrate 200ms, delay 250ms, vibrate 200ms
      long[] vibrate = {0, 200, 250, 200};
      builder.setVibrate(vibrate);
    } else {
      logger.d("notification#setting is not using vibration");
    }

    // sound
    if (configurationSp.getCfg(SysConstant.SETTING_GLOBAL, ConfigurationSp.CfgDimension.SOUND)) {
      builder.setDefaults(Notification.DEFAULT_SOUND);
    } else {
      logger.d("notification#setting is not using sound");
    }
    if (iconBitmap != null) {
      logger.d("notification#fetch icon from network ok");
      builder.setLargeIcon(iconBitmap);
    } else {
      // do nothint ?
    }
    // if MessageActivity is in the background, the system would bring it to
    // the front
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent pendingIntent =
        PendingIntent.getActivity(ctx, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    builder.setContentIntent(pendingIntent);
    Notification notification = builder.build();
    notifyMgr.notify(notificationId, notification);
  }
  public void add(MessageEntity msg) {
    // 更新session list中的msg信息
    // 更新未读消息计数
    if (msg == null) {
      logger.d("unread#unreadMgr#add msg is null!");
      return;
    }
    // isFirst场景:出现一条未读消息,出现小红点,需要触发 [免打扰的情况下]
    boolean isFirst = false;
    logger.d("unread#unreadMgr#add unread msg:%s", msg);
    UnreadEntity unreadEntity;
    int loginId = IMLoginManager.instance().getLoginId();
    String sessionKey = msg.getSessionKey();
    boolean isSend = msg.isSend(loginId);
    if (isSend) {
      IMNotificationManager.instance().cancelSessionNotifications(sessionKey);
      return;
    }

    if (unreadMsgMap.containsKey(sessionKey)) {
      unreadEntity = unreadMsgMap.get(sessionKey);
      // 判断最后一条msgId是否相同
      if (unreadEntity.getLaststMsgId() == msg.getMsgId()) {
        return;
      }
      unreadEntity.setUnReadCnt(unreadEntity.getUnReadCnt() + 1);
    } else {
      isFirst = true;
      unreadEntity = new UnreadEntity();
      unreadEntity.setUnReadCnt(1);
      unreadEntity.setPeerId(msg.getPeerId(isSend));
      unreadEntity.setSessionType(msg.getSessionType());
      unreadEntity.buildSessionKey();
    }

    unreadEntity.setLatestMsgData(msg.getMessageDisplay());
    unreadEntity.setLaststMsgId(msg.getMsgId());
    addIsForbidden(unreadEntity);

    /** 放入manager 状态中 */
    unreadMsgMap.put(unreadEntity.getSessionKey(), unreadEntity);

    /** 没有被屏蔽才会发送广播 */
    if (!unreadEntity.isForbidden() || isFirst) {
      UnreadEvent unreadEvent = new UnreadEvent();
      unreadEvent.event = UnreadEvent.Event.UNREAD_MSG_RECEIVED;
      unreadEvent.entity = unreadEntity;
      triggerEvent(unreadEvent);
    }
  }
  public void onRepUnreadMsgContactList(IMMessage.IMUnreadMsgCntRsp unreadMsgCntRsp) {
    logger.i("unread#2onRepUnreadMsgContactList");
    totalUnreadCount = unreadMsgCntRsp.getTotalCnt();
    List<IMBaseDefine.UnreadInfo> unreadInfoList = unreadMsgCntRsp.getUnreadinfoListList();
    logger.i(
        "unread#unreadMsgCnt:%d, unreadMsgInfoCnt:%d", unreadInfoList.size(), totalUnreadCount);

    for (IMBaseDefine.UnreadInfo unreadInfo : unreadInfoList) {
      UnreadEntity unreadEntity = ProtoBuf2JavaBean.getUnreadEntity(unreadInfo);
      // 屏蔽的设定
      addIsForbidden(unreadEntity);
      unreadMsgMap.put(unreadEntity.getSessionKey(), unreadEntity);
    }
    triggerEvent(new UnreadEvent(UnreadEvent.Event.UNREAD_MSG_LIST_OK));
  }
Пример #8
0
 public GroupEntity findGroup(int groupId) {
   logger.d("group#findGroup groupId:%s", groupId);
   if (groupMap.containsKey(groupId)) {
     return groupMap.get(groupId);
   }
   return null;
 }
Пример #9
0
  /** 1. 加载本地信息 2. 从session中获取 群组信息,从本地中获取这些群组的version信息 3. 合并上述的merge结果, version groupId 请求 */
  private void loadSessionGroupInfo() {
    logger.i("group#loadSessionGroupInfo");

    List<SessionEntity> sessionInfoList = IMSessionManager.instance().getRecentSessionList();

    List<IMBaseDefine.GroupVersionInfo> needReqList = new ArrayList<>();
    for (SessionEntity sessionInfo : sessionInfoList) {
      int version = 0;
      if (sessionInfo.getPeerType() == DBConstant.SESSION_TYPE_GROUP
      /** 群组 */
      ) {
        if (groupMap.containsKey(sessionInfo.getPeerId())) {
          version = groupMap.get(sessionInfo.getPeerId()).getVersion();
        }

        IMBaseDefine.GroupVersionInfo versionInfo =
            IMBaseDefine.GroupVersionInfo.newBuilder()
                .setVersion(version)
                .setGroupId(sessionInfo.getPeerId())
                .build();
        needReqList.add(versionInfo);
      }
    }
    // 事件触发的时候需要注意
    if (needReqList.size() > 0) {
      reqGetGroupDetailInfo(needReqList);
      return;
    }
  }
Пример #10
0
  /** 请求群组的详细信息 */
  public void reqGetGroupDetailInfo(List<IMBaseDefine.GroupVersionInfo> versionInfoList) {
    logger.i("group#reqGetGroupDetailInfo");
    if (versionInfoList == null || versionInfoList.size() <= 0) {
      logger.e("group#reqGetGroupDetailInfo# please check your params,cause by empty/null");
      return;
    }
    int loginId = imLoginManager.getLoginId();
    IMGroup.IMGroupInfoListReq groupInfoListReq =
        IMGroup.IMGroupInfoListReq.newBuilder()
            .setUserId(loginId)
            .addAllGroupVersionList(versionInfoList)
            .build();

    int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
    int cid = IMBaseDefine.GroupCmdID.CID_GROUP_INFO_REQUEST_VALUE;
    imSocketManager.sendRequest(groupInfoListReq, sid, cid);
  }
Пример #11
0
  public void onReqCreateTempGroup(IMGroup.IMGroupCreateRsp groupCreateRsp) {
    logger.d("group#onReqCreateTempGroup");

    int resultCode = groupCreateRsp.getResultCode();
    if (0 != resultCode) {
      logger.e("group#createGroup failed");
      triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_FAIL));
      return;
    }
    GroupEntity groupEntity = ProtoBuf2JavaBean.getGroupEntity(groupCreateRsp);
    // 更新DB 更新map
    groupMap.put(groupEntity.getPeerId(), groupEntity);

    IMSessionManager.instance().updateSession(groupEntity);
    dbInterface.insertOrUpdateGroup(groupEntity);
    triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_OK, groupEntity)); // 接收到之后修改UI
  }
 /**
  * 备注: 先获取最后一条消息 1. 清除回话内的未读计数 2. 发送最后一条msgId的已读确认
  *
  * @param sessionKey
  */
 public void readUnreadSession(String sessionKey) {
   logger.d("unread#readUnreadSession# sessionKey:%s", sessionKey);
   if (unreadMsgMap.containsKey(sessionKey)) {
     UnreadEntity entity = unreadMsgMap.remove(sessionKey);
     ackReadMsg(entity);
     triggerEvent(new UnreadEvent(UnreadEvent.Event.SESSION_READED_UNREAD_MSG));
   }
 }
 /** 请求未读消息列表 */
 private void reqUnreadMsgContactList() {
   logger.i("unread#1reqUnreadMsgContactList");
   int loginId = IMLoginManager.instance().getLoginId();
   IMMessage.IMUnreadMsgCntReq unreadMsgCntReq =
       IMMessage.IMUnreadMsgCntReq.newBuilder().setUserId(loginId).build();
   int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE;
   int cid = IMBaseDefine.MessageCmdID.CID_MSG_UNREAD_CNT_REQUEST_VALUE;
   imSocketManager.sendRequest(unreadMsgCntReq, sid, cid);
 }
 /**
  * 在通知栏中删除特定回话的状态
  *
  * @param sessionKey
  */
 public void cancelSessionNotifications(String sessionKey) {
   logger.d("notification#cancelSessionNotifications");
   NotificationManager notifyMgr =
       (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
   if (null == notifyMgr) {
     return;
   }
   int notificationId = getSessionNotificationId(sessionKey);
   notifyMgr.cancel(notificationId);
 }
  private void handleMsgRecv(UnreadEntity entity) {
    logger.d("notification#recv unhandled message");
    int peerId = entity.getPeerId();
    int sessionType = entity.getSessionType();
    logger.d("notification#msg no one handled, peerId:%d, sessionType:%d", peerId, sessionType);

    // 判断是否设定了免打扰
    if (entity.isForbidden()) {
      logger.d("notification#GROUP_STATUS_SHIELD");
      return;
    }

    // PC端是否登陆 取消 【暂时先关闭】
    //        if(IMLoginManager.instance().isPcOnline()){
    //            logger.d("notification#isPcOnline");
    //            return;
    //        }

    // 全局开关
    boolean globallyOnOff =
        configurationSp.getCfg(
            SysConstant.SETTING_GLOBAL, ConfigurationSp.CfgDimension.NOTIFICATION);
    if (globallyOnOff) {
      logger.d("notification#shouldGloballyShowNotification is false, return");
      return;
    }

    // 单独的设置
    boolean singleOnOff =
        configurationSp.getCfg(entity.getSessionKey(), ConfigurationSp.CfgDimension.NOTIFICATION);
    if (singleOnOff) {
      logger.d("notification#shouldShowNotificationBySession is false, return");
      return;
    }

    // if the message is a multi login message which send from another terminal,not need notificate
    // to status bar
    // 判断是否是自己的消息
    if (IMLoginManager.instance().getLoginId() != peerId) {
      showNotification(entity);
    }
  }
Пример #16
0
  public List<UserEntity> getGroupMembers(int groupId) {
    logger.d("group#getGroupMembers groupId:%s", groupId);

    GroupEntity group = findGroup(groupId);
    if (group == null) {
      logger.e("group#no such group id:%s", groupId);
      return null;
    }
    Set<Integer> userList = group.getlistGroupMemberIds();
    ArrayList<UserEntity> memberList = new ArrayList<UserEntity>();
    for (Integer id : userList) {
      UserEntity contact = IMContactManager.instance().findContact(id);
      if (contact == null) {
        logger.e("group#no such contact id:%s", id);
        continue;
      }
      memberList.add(contact);
    }
    return memberList;
  }
 public void cancelAllNotifications() {
   logger.d("notification#cancelAllNotifications");
   if (null == ctx) {
     return;
   }
   NotificationManager notifyMgr =
       (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
   if (notifyMgr == null) {
     return;
   }
   notifyMgr.cancelAll();
 }
Пример #18
0
  public void onRepGroupDetailInfo(IMGroup.IMGroupInfoListRsp groupInfoListRsp) {
    logger.i("group#onRepGroupDetailInfo");
    int groupSize = groupInfoListRsp.getGroupInfoListCount();
    int userId = groupInfoListRsp.getUserId();
    int loginId = imLoginManager.getLoginId();
    logger.i("group#onRepGroupDetailInfo cnt:%d", groupSize);
    if (groupSize <= 0 || userId != loginId) {
      logger.i("group#onRepGroupDetailInfo size empty or userid[%d]≠ loginId[%d]", userId, loginId);
      return;
    }
    ArrayList<GroupEntity> needDb = new ArrayList<>();
    for (IMBaseDefine.GroupInfo groupInfo : groupInfoListRsp.getGroupInfoListList()) {
      // 群组的详细信息
      // 保存在DB中
      // GroupManager 中的变量
      GroupEntity groupEntity = ProtoBuf2JavaBean.getGroupEntity(groupInfo);
      groupMap.put(groupEntity.getPeerId(), groupEntity);
      needDb.add(groupEntity);
    }

    dbInterface.batchInsertOrUpdateGroup(needDb);
    triggerEvent(new GroupEvent(GroupEvent.Event.GROUP_INFO_UPDATED));
  }
Пример #19
0
  /** 1. 加载本地信息 2. 请求正规群信息 , 与本地进行对比 3. version groupId 请求 */
  public void onLocalLoginOk() {
    logger.i("group#loadFromDb");

    if (!EventBus.getDefault().isRegistered(inst)) {
      EventBus.getDefault().registerSticky(inst);
    }

    // 加载本地group
    List<GroupEntity> localGroupInfoList = dbInterface.loadAllGroup();
    for (GroupEntity groupInfo : localGroupInfoList) {
      groupMap.put(groupInfo.getPeerId(), groupInfo);
    }

    triggerEvent(new GroupEvent(GroupEvent.Event.GROUP_INFO_OK));
  }
 public void ackReadMsg(UnreadEntity unreadEntity) {
   logger.d("chat#ackReadMsg -> msg:%s", unreadEntity);
   int loginId = loginManager.getLoginId();
   IMBaseDefine.SessionType sessionType =
       Java2ProtoBuf.getProtoSessionType(unreadEntity.getSessionType());
   IMMessage.IMMsgDataReadAck readAck =
       IMMessage.IMMsgDataReadAck.newBuilder()
           .setMsgId(unreadEntity.getLaststMsgId())
           .setSessionId(unreadEntity.getPeerId())
           .setSessionType(sessionType)
           .setUserId(loginId)
           .build();
   int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE;
   int cid = IMBaseDefine.MessageCmdID.CID_MSG_READ_ACK_VALUE;
   imSocketManager.sendRequest(readAck, sid, cid);
 }
Пример #21
0
  /** 创建群 默认是创建临时群,且客户端只能创建临时群 */
  public void reqCreateTempGroup(String groupName, Set<Integer> memberList) {

    logger.i("group#reqCreateTempGroup, tempGroupName = %s", groupName);

    int loginId = imLoginManager.getLoginId();

    IMGroup.IMGroupCreateReq groupCreateReq =
        IMGroup.IMGroupCreateReq.newBuilder()
            .setUserId(loginId)
            .setGroupType(IMBaseDefine.GroupType.GROUP_TYPE_TMP)
            .setGroupName(groupName)
            .setGroupAvatar("") // todo 群头像 现在是四宫格
            .addAllMemberIdList(memberList)
            .build();

    int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
    int cid = IMBaseDefine.GroupCmdID.CID_GROUP_CREATE_REQUEST_VALUE;
    imSocketManager.sendRequest(
        groupCreateReq,
        sid,
        cid,
        new Packetlistener() {
          @Override
          public void onSuccess(Object response) {
            try {
              IMGroup.IMGroupCreateRsp groupCreateRsp =
                  IMGroup.IMGroupCreateRsp.parseFrom((CodedInputStream) response);
              IMGroupManager.instance().onReqCreateTempGroup(groupCreateRsp);
            } catch (IOException e) {
              logger.e("reqCreateTempGroup parse error");
              triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_FAIL));
            }
          }

          @Override
          public void onFaild() {
            triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_FAIL));
          }

          @Override
          public void onTimeout() {
            triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_TIMEOUT));
          }
        });
  }
Пример #22
0
  private void reqChangeGroupMember(
      int groupId, IMBaseDefine.GroupModifyType groupModifyType, Set<Integer> changeMemberlist) {
    logger.i("group#reqChangeGroupMember, changeGroupMemberType = %s", groupModifyType.toString());

    final int loginId = imLoginManager.getLoginId();
    IMGroup.IMGroupChangeMemberReq groupChangeMemberReq =
        IMGroup.IMGroupChangeMemberReq.newBuilder()
            .setUserId(loginId)
            .setChangeType(groupModifyType)
            .addAllMemberIdList(changeMemberlist)
            .setGroupId(groupId)
            .build();

    int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
    int cid = IMBaseDefine.GroupCmdID.CID_GROUP_CHANGE_MEMBER_REQUEST_VALUE;
    imSocketManager.sendRequest(
        groupChangeMemberReq,
        sid,
        cid,
        new Packetlistener() {
          @Override
          public void onSuccess(Object response) {
            try {
              IMGroup.IMGroupChangeMemberRsp groupChangeMemberRsp =
                  IMGroup.IMGroupChangeMemberRsp.parseFrom((CodedInputStream) response);
              IMGroupManager.instance().onReqChangeGroupMember(groupChangeMemberRsp);
            } catch (IOException e) {
              logger.e("reqChangeGroupMember parse error!");
              triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_FAIL));
            }
          }

          @Override
          public void onFaild() {
            triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_FAIL));
          }

          @Override
          public void onTimeout() {
            triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_TIMEOUT));
          }
        });
  }
/** 未读消息相关的处理,归属于messageEvent中 可以理解为MessageManager的又一次拆分 为session提供未读支持。 DB 中不保存 */
public class IMUnreadMsgManager extends IMManager {
  private Logger logger = Logger.getLogger(IMUnreadMsgManager.class);
  private static IMUnreadMsgManager inst = new IMUnreadMsgManager();

  public static IMUnreadMsgManager instance() {
    return inst;
  }

  private IMSocketManager imSocketManager = IMSocketManager.instance();
  private IMLoginManager loginManager = IMLoginManager.instance();

  /** key=> sessionKey */
  private ConcurrentHashMap<String, UnreadEntity> unreadMsgMap = new ConcurrentHashMap<>();

  private int totalUnreadCount = 0;

  private boolean unreadListReady = false;

  @Override
  public void doOnStart() {}

  // 未读消息控制器,本地是不存状态的
  public void onNormalLoginOk() {
    unreadMsgMap.clear();
    reqUnreadMsgContactList();
  }

  public void onLocalNetOk() {
    unreadMsgMap.clear();
    reqUnreadMsgContactList();
  }

  @Override
  public void reset() {
    unreadListReady = false;
    unreadMsgMap.clear();
  }

  /**
   * 继承该方法实现自身的事件驱动
   *
   * @param event
   */
  public synchronized void triggerEvent(UnreadEvent event) {
    switch (event.event) {
      case UNREAD_MSG_LIST_OK:
        unreadListReady = true;
        break;
    }

    EventBus.getDefault().post(event);
  }

  /** -------------------------------分割线---------------------------------- */
  /** 请求未读消息列表 */
  private void reqUnreadMsgContactList() {
    logger.i("unread#1reqUnreadMsgContactList");
    int loginId = IMLoginManager.instance().getLoginId();
    IMMessage.IMUnreadMsgCntReq unreadMsgCntReq =
        IMMessage.IMUnreadMsgCntReq.newBuilder().setUserId(loginId).build();
    int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE;
    int cid = IMBaseDefine.MessageCmdID.CID_MSG_UNREAD_CNT_REQUEST_VALUE;
    imSocketManager.sendRequest(unreadMsgCntReq, sid, cid);
  }

  public void onRepUnreadMsgContactList(IMMessage.IMUnreadMsgCntRsp unreadMsgCntRsp) {
    logger.i("unread#2onRepUnreadMsgContactList");
    totalUnreadCount = unreadMsgCntRsp.getTotalCnt();
    List<IMBaseDefine.UnreadInfo> unreadInfoList = unreadMsgCntRsp.getUnreadinfoListList();
    logger.i(
        "unread#unreadMsgCnt:%d, unreadMsgInfoCnt:%d", unreadInfoList.size(), totalUnreadCount);

    for (IMBaseDefine.UnreadInfo unreadInfo : unreadInfoList) {
      UnreadEntity unreadEntity = ProtoBuf2JavaBean.getUnreadEntity(unreadInfo);
      // 屏蔽的设定
      addIsForbidden(unreadEntity);
      unreadMsgMap.put(unreadEntity.getSessionKey(), unreadEntity);
    }
    triggerEvent(new UnreadEvent(UnreadEvent.Event.UNREAD_MSG_LIST_OK));
  }

  /**
   * 回话是否已经被设定为屏蔽
   *
   * @param unreadEntity
   */
  private void addIsForbidden(UnreadEntity unreadEntity) {
    if (unreadEntity.getSessionType() == DBConstant.SESSION_TYPE_GROUP) {
      GroupEntity groupEntity = IMGroupManager.instance().findGroup(unreadEntity.getPeerId());
      if (groupEntity != null && groupEntity.getStatus() == DBConstant.GROUP_STATUS_SHIELD) {
        unreadEntity.setForbidden(true);
      }
    }
  }

  /** 设定未读回话为屏蔽回话 仅限于群组 todo */
  public void setForbidden(String sessionKey, boolean isFor) {
    UnreadEntity unreadEntity = unreadMsgMap.get(sessionKey);
    if (unreadEntity != null) {
      unreadEntity.setForbidden(isFor);
    }
  }

  public void add(MessageEntity msg) {
    // 更新session list中的msg信息
    // 更新未读消息计数
    if (msg == null) {
      logger.d("unread#unreadMgr#add msg is null!");
      return;
    }
    // isFirst场景:出现一条未读消息,出现小红点,需要触发 [免打扰的情况下]
    boolean isFirst = false;
    logger.d("unread#unreadMgr#add unread msg:%s", msg);
    UnreadEntity unreadEntity;
    int loginId = IMLoginManager.instance().getLoginId();
    String sessionKey = msg.getSessionKey();
    boolean isSend = msg.isSend(loginId);
    if (isSend) {
      IMNotificationManager.instance().cancelSessionNotifications(sessionKey);
      return;
    }

    if (unreadMsgMap.containsKey(sessionKey)) {
      unreadEntity = unreadMsgMap.get(sessionKey);
      // 判断最后一条msgId是否相同
      if (unreadEntity.getLaststMsgId() == msg.getMsgId()) {
        return;
      }
      unreadEntity.setUnReadCnt(unreadEntity.getUnReadCnt() + 1);
    } else {
      isFirst = true;
      unreadEntity = new UnreadEntity();
      unreadEntity.setUnReadCnt(1);
      unreadEntity.setPeerId(msg.getPeerId(isSend));
      unreadEntity.setSessionType(msg.getSessionType());
      unreadEntity.buildSessionKey();
    }

    unreadEntity.setLatestMsgData(msg.getMessageDisplay());
    unreadEntity.setLaststMsgId(msg.getMsgId());
    addIsForbidden(unreadEntity);

    /** 放入manager 状态中 */
    unreadMsgMap.put(unreadEntity.getSessionKey(), unreadEntity);

    /** 没有被屏蔽才会发送广播 */
    if (!unreadEntity.isForbidden() || isFirst) {
      UnreadEvent unreadEvent = new UnreadEvent();
      unreadEvent.event = UnreadEvent.Event.UNREAD_MSG_RECEIVED;
      unreadEvent.entity = unreadEntity;
      triggerEvent(unreadEvent);
    }
  }

  public void ackReadMsg(MessageEntity entity) {
    logger.d("chat#ackReadMsg -> msg:%s", entity);
    int loginId = loginManager.getLoginId();
    IMBaseDefine.SessionType sessionType =
        Java2ProtoBuf.getProtoSessionType(entity.getSessionType());
    IMMessage.IMMsgDataReadAck readAck =
        IMMessage.IMMsgDataReadAck.newBuilder()
            .setMsgId(entity.getMsgId())
            .setSessionId(entity.getPeerId(false))
            .setSessionType(sessionType)
            .setUserId(loginId)
            .build();
    int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE;
    int cid = IMBaseDefine.MessageCmdID.CID_MSG_READ_ACK_VALUE;
    imSocketManager.sendRequest(readAck, sid, cid);
  }

  public void ackReadMsg(UnreadEntity unreadEntity) {
    logger.d("chat#ackReadMsg -> msg:%s", unreadEntity);
    int loginId = loginManager.getLoginId();
    IMBaseDefine.SessionType sessionType =
        Java2ProtoBuf.getProtoSessionType(unreadEntity.getSessionType());
    IMMessage.IMMsgDataReadAck readAck =
        IMMessage.IMMsgDataReadAck.newBuilder()
            .setMsgId(unreadEntity.getLaststMsgId())
            .setSessionId(unreadEntity.getPeerId())
            .setSessionType(sessionType)
            .setUserId(loginId)
            .build();
    int sid = IMBaseDefine.ServiceID.SID_MSG_VALUE;
    int cid = IMBaseDefine.MessageCmdID.CID_MSG_READ_ACK_VALUE;
    imSocketManager.sendRequest(readAck, sid, cid);
  }

  /**
   * 服务端主动发送已读通知
   *
   * @param readNotify
   */
  public void onNotifyRead(IMMessage.IMMsgDataReadNotify readNotify) {
    logger.d("chat#onNotifyRead");
    // 发送此信令的用户id
    int trigerId = readNotify.getUserId();
    int loginId = IMLoginManager.instance().getLoginId();
    if (trigerId != loginId) {
      logger.i("onNotifyRead# trigerId:%s,loginId:%s not Equal", trigerId, loginId);
      return;
    }
    // 现在的逻辑是msgId之后的 全部都是已读的
    // 不做复杂判断了,简单处理
    int msgId = readNotify.getMsgId();
    int peerId = readNotify.getSessionId();
    int sessionType = ProtoBuf2JavaBean.getJavaSessionType(readNotify.getSessionType());
    String sessionKey = EntityChangeEngine.getSessionKey(peerId, sessionType);

    // 通知栏也要去除掉
    NotificationManager notifyMgr =
        (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
    if (notifyMgr == null) {
      return;
    }
    int notificationId = IMNotificationManager.instance().getSessionNotificationId(sessionKey);
    notifyMgr.cancel(notificationId);

    UnreadEntity unreadSession = findUnread(sessionKey);
    if (unreadSession != null && unreadSession.getLaststMsgId() <= msgId) {
      // 清空会话session
      logger.d("chat#onNotifyRead# unreadSession onLoginOut");
      readUnreadSession(sessionKey);
    }
  }

  /**
   * 备注: 先获取最后一条消息 1. 清除回话内的未读计数 2. 发送最后一条msgId的已读确认
   *
   * @param sessionKey
   */
  public void readUnreadSession(String sessionKey) {
    logger.d("unread#readUnreadSession# sessionKey:%s", sessionKey);
    if (unreadMsgMap.containsKey(sessionKey)) {
      UnreadEntity entity = unreadMsgMap.remove(sessionKey);
      ackReadMsg(entity);
      triggerEvent(new UnreadEvent(UnreadEvent.Event.SESSION_READED_UNREAD_MSG));
    }
  }

  public UnreadEntity findUnread(String sessionKey) {
    logger.d("unread#findUnread# buddyId:%s", sessionKey);
    if (TextUtils.isEmpty(sessionKey) || unreadMsgMap.size() <= 0) {
      logger.i("unread#findUnread# no unread info");
      return null;
    }
    if (unreadMsgMap.containsKey(sessionKey)) {
      return unreadMsgMap.get(sessionKey);
    }
    return null;
  }

  /** ----------------实体set/get------------------------------- */
  public ConcurrentHashMap<String, UnreadEntity> getUnreadMsgMap() {
    return unreadMsgMap;
  }

  public int getTotalUnreadCount() {
    int count = 0;
    for (UnreadEntity entity : unreadMsgMap.values()) {
      if (!entity.isForbidden()) {
        count = count + entity.getUnReadCnt();
      }
    }
    return count;
  }

  public boolean isUnreadListReady() {
    return unreadListReady;
  }
}
Пример #24
0
  /** 屏蔽群消息 IMGroupShieldReq 备注:应为屏蔽之后大部分操作依旧需要客户端做 */
  public void reqShieldGroup(final int groupId, final int shieldType) {
    final GroupEntity entity = groupMap.get(groupId);
    if (entity == null) {
      logger.i("GroupEntity do not exist!");
      return;
    }
    final int loginId = IMLoginManager.instance().getLoginId();
    IMGroup.IMGroupShieldReq shieldReq =
        IMGroup.IMGroupShieldReq.newBuilder()
            .setShieldStatus(shieldType)
            .setGroupId(groupId)
            .setUserId(loginId)
            .build();
    int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
    int cid = IMBaseDefine.GroupCmdID.CID_GROUP_SHIELD_GROUP_REQUEST_VALUE;
    imSocketManager.sendRequest(
        shieldReq,
        sid,
        cid,
        new Packetlistener() {
          @Override
          public void onSuccess(Object response) {
            try {
              IMGroup.IMGroupShieldRsp groupShieldRsp =
                  IMGroup.IMGroupShieldRsp.parseFrom((CodedInputStream) response);
              int resCode = groupShieldRsp.getResultCode();
              if (resCode != 0) {
                triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_FAIL));
                return;
              }
              if (groupShieldRsp.getGroupId() != groupId || groupShieldRsp.getUserId() != loginId) {
                return;
              }
              // 更新DB状态
              entity.setStatus(shieldType);
              dbInterface.insertOrUpdateGroup(entity);
              // 更改未读计数状态
              boolean isFor = shieldType == DBConstant.GROUP_STATUS_SHIELD;
              IMUnreadMsgManager.instance()
                  .setForbidden(
                      EntityChangeEngine.getSessionKey(groupId, DBConstant.SESSION_TYPE_GROUP),
                      isFor);
              triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_OK, entity));

            } catch (IOException e) {
              logger.e("reqChangeGroupMember parse error!");
              triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_FAIL));
            }
          }

          @Override
          public void onFaild() {
            triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_FAIL));
          }

          @Override
          public void onTimeout() {
            triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_TIMEOUT));
          }
        });
  }
Пример #25
0
public class IMGroupManager extends IMManager {
  private Logger logger = Logger.getLogger(IMGroupManager.class);
  private static IMGroupManager inst = new IMGroupManager();

  public static IMGroupManager instance() {
    return inst;
  }

  // 依赖的服务管理
  private IMSocketManager imSocketManager = IMSocketManager.instance();
  private IMLoginManager imLoginManager = IMLoginManager.instance();
  private DBInterface dbInterface = DBInterface.instance();

  // todo Pinyin的处理
  // 正式群,临时群都会有的,存在竞争 如果不同时请求的话
  private Map<Integer, GroupEntity> groupMap = new ConcurrentHashMap<>();
  // 群组状态
  private boolean isGroupReady = false;

  @Override
  public void doOnStart() {
    groupMap.clear();
  }

  public void onNormalLoginOk() {
    onLocalLoginOk();
    onLocalNetOk();
  }

  /** 1. 加载本地信息 2. 请求正规群信息 , 与本地进行对比 3. version groupId 请求 */
  public void onLocalLoginOk() {
    logger.i("group#loadFromDb");

    if (!EventBus.getDefault().isRegistered(inst)) {
      EventBus.getDefault().registerSticky(inst);
    }

    // 加载本地group
    List<GroupEntity> localGroupInfoList = dbInterface.loadAllGroup();
    for (GroupEntity groupInfo : localGroupInfoList) {
      groupMap.put(groupInfo.getPeerId(), groupInfo);
    }

    triggerEvent(new GroupEvent(GroupEvent.Event.GROUP_INFO_OK));
  }

  public void onLocalNetOk() {
    reqGetNormalGroupList();
  }

  @Override
  public void reset() {
    isGroupReady = false;
    groupMap.clear();
    EventBus.getDefault().unregister(inst);
  }

  public void onEvent(SessionEvent event) {
    switch (event) {
      case RECENT_SESSION_LIST_UPDATE:
        // groupMap 本地已经加载完毕之后才触发
        loadSessionGroupInfo();
        break;
    }
  }

  /**
   * 实现自身的事件驱动
   *
   * @param event
   */
  public synchronized void triggerEvent(GroupEvent event) {
    switch (event.getEvent()) {
      case GROUP_INFO_OK:
        isGroupReady = true;
        break;
      case GROUP_INFO_UPDATED:
        isGroupReady = true;
        break;
    }
    EventBus.getDefault().postSticky(event);
  }

  /** ---------------事件驱动end------------------------------ */

  /** 1. 加载本地信息 2. 从session中获取 群组信息,从本地中获取这些群组的version信息 3. 合并上述的merge结果, version groupId 请求 */
  private void loadSessionGroupInfo() {
    logger.i("group#loadSessionGroupInfo");

    List<SessionEntity> sessionInfoList = IMSessionManager.instance().getRecentSessionList();

    List<IMBaseDefine.GroupVersionInfo> needReqList = new ArrayList<>();
    for (SessionEntity sessionInfo : sessionInfoList) {
      int version = 0;
      if (sessionInfo.getPeerType() == DBConstant.SESSION_TYPE_GROUP
      /** 群组 */
      ) {
        if (groupMap.containsKey(sessionInfo.getPeerId())) {
          version = groupMap.get(sessionInfo.getPeerId()).getVersion();
        }

        IMBaseDefine.GroupVersionInfo versionInfo =
            IMBaseDefine.GroupVersionInfo.newBuilder()
                .setVersion(version)
                .setGroupId(sessionInfo.getPeerId())
                .build();
        needReqList.add(versionInfo);
      }
    }
    // 事件触发的时候需要注意
    if (needReqList.size() > 0) {
      reqGetGroupDetailInfo(needReqList);
      return;
    }
  }

  /** 联系人页面正式群的请求 todo 正式群与临时群逻辑上的分开的,但是底层应该是想通的 */
  private void reqGetNormalGroupList() {
    logger.i("group#reqGetNormalGroupList");
    int loginId = imLoginManager.getLoginId();
    IMGroup.IMNormalGroupListReq normalGroupListReq =
        IMGroup.IMNormalGroupListReq.newBuilder().setUserId(loginId).build();
    int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
    int cid = IMBaseDefine.GroupCmdID.CID_GROUP_NORMAL_LIST_REQUEST_VALUE;
    imSocketManager.sendRequest(normalGroupListReq, sid, cid);
    logger.i("group#send packet to server");
  }

  public void onRepNormalGroupList(IMGroup.IMNormalGroupListRsp normalGroupListRsp) {
    logger.i("group#onRepNormalGroupList");
    int groupSize = normalGroupListRsp.getGroupVersionListCount();
    logger.i("group#onRepNormalGroupList cnt:%d", groupSize);
    List<IMBaseDefine.GroupVersionInfo> versionInfoList =
        normalGroupListRsp.getGroupVersionListList();

    /** 对比DB中的version字段 */
    // 这块对比的可以抽离出来
    List<IMBaseDefine.GroupVersionInfo> needInfoList = new ArrayList<>();

    for (IMBaseDefine.GroupVersionInfo groupVersionInfo : versionInfoList) {
      int groupId = groupVersionInfo.getGroupId();
      int version = groupVersionInfo.getVersion();
      if (groupMap.containsKey(groupId) && groupMap.get(groupId).getVersion() == version) {
        continue;
      }
      IMBaseDefine.GroupVersionInfo versionInfo =
          IMBaseDefine.GroupVersionInfo.newBuilder().setVersion(0).setGroupId(groupId).build();
      needInfoList.add(versionInfo);
    }

    // 事件触发的时候需要注意 todo
    if (needInfoList.size() > 0) {
      reqGetGroupDetailInfo(needInfoList);
    }
  }

  public void reqGroupDetailInfo(int groupId) {
    IMBaseDefine.GroupVersionInfo groupVersionInfo =
        IMBaseDefine.GroupVersionInfo.newBuilder().setGroupId(groupId).setVersion(0).build();
    ArrayList<IMBaseDefine.GroupVersionInfo> list = new ArrayList<>();
    list.add(groupVersionInfo);
    reqGetGroupDetailInfo(list);
  }

  /** 请求群组的详细信息 */
  public void reqGetGroupDetailInfo(List<IMBaseDefine.GroupVersionInfo> versionInfoList) {
    logger.i("group#reqGetGroupDetailInfo");
    if (versionInfoList == null || versionInfoList.size() <= 0) {
      logger.e("group#reqGetGroupDetailInfo# please check your params,cause by empty/null");
      return;
    }
    int loginId = imLoginManager.getLoginId();
    IMGroup.IMGroupInfoListReq groupInfoListReq =
        IMGroup.IMGroupInfoListReq.newBuilder()
            .setUserId(loginId)
            .addAllGroupVersionList(versionInfoList)
            .build();

    int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
    int cid = IMBaseDefine.GroupCmdID.CID_GROUP_INFO_REQUEST_VALUE;
    imSocketManager.sendRequest(groupInfoListReq, sid, cid);
  }

  public void onRepGroupDetailInfo(IMGroup.IMGroupInfoListRsp groupInfoListRsp) {
    logger.i("group#onRepGroupDetailInfo");
    int groupSize = groupInfoListRsp.getGroupInfoListCount();
    int userId = groupInfoListRsp.getUserId();
    int loginId = imLoginManager.getLoginId();
    logger.i("group#onRepGroupDetailInfo cnt:%d", groupSize);
    if (groupSize <= 0 || userId != loginId) {
      logger.i("group#onRepGroupDetailInfo size empty or userid[%d]≠ loginId[%d]", userId, loginId);
      return;
    }
    ArrayList<GroupEntity> needDb = new ArrayList<>();
    for (IMBaseDefine.GroupInfo groupInfo : groupInfoListRsp.getGroupInfoListList()) {
      // 群组的详细信息
      // 保存在DB中
      // GroupManager 中的变量
      GroupEntity groupEntity = ProtoBuf2JavaBean.getGroupEntity(groupInfo);
      groupMap.put(groupEntity.getPeerId(), groupEntity);
      needDb.add(groupEntity);
    }

    dbInterface.batchInsertOrUpdateGroup(needDb);
    triggerEvent(new GroupEvent(GroupEvent.Event.GROUP_INFO_UPDATED));
  }

  /** 创建群 默认是创建临时群,且客户端只能创建临时群 */
  public void reqCreateTempGroup(String groupName, Set<Integer> memberList) {

    logger.i("group#reqCreateTempGroup, tempGroupName = %s", groupName);

    int loginId = imLoginManager.getLoginId();

    IMGroup.IMGroupCreateReq groupCreateReq =
        IMGroup.IMGroupCreateReq.newBuilder()
            .setUserId(loginId)
            .setGroupType(IMBaseDefine.GroupType.GROUP_TYPE_TMP)
            .setGroupName(groupName)
            .setGroupAvatar("") // todo 群头像 现在是四宫格
            .addAllMemberIdList(memberList)
            .build();

    int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
    int cid = IMBaseDefine.GroupCmdID.CID_GROUP_CREATE_REQUEST_VALUE;
    imSocketManager.sendRequest(
        groupCreateReq,
        sid,
        cid,
        new Packetlistener() {
          @Override
          public void onSuccess(Object response) {
            try {
              IMGroup.IMGroupCreateRsp groupCreateRsp =
                  IMGroup.IMGroupCreateRsp.parseFrom((CodedInputStream) response);
              IMGroupManager.instance().onReqCreateTempGroup(groupCreateRsp);
            } catch (IOException e) {
              logger.e("reqCreateTempGroup parse error");
              triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_FAIL));
            }
          }

          @Override
          public void onFaild() {
            triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_FAIL));
          }

          @Override
          public void onTimeout() {
            triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_TIMEOUT));
          }
        });
  }

  public void onReqCreateTempGroup(IMGroup.IMGroupCreateRsp groupCreateRsp) {
    logger.d("group#onReqCreateTempGroup");

    int resultCode = groupCreateRsp.getResultCode();
    if (0 != resultCode) {
      logger.e("group#createGroup failed");
      triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_FAIL));
      return;
    }
    GroupEntity groupEntity = ProtoBuf2JavaBean.getGroupEntity(groupCreateRsp);
    // 更新DB 更新map
    groupMap.put(groupEntity.getPeerId(), groupEntity);

    IMSessionManager.instance().updateSession(groupEntity);
    dbInterface.insertOrUpdateGroup(groupEntity);
    triggerEvent(new GroupEvent(GroupEvent.Event.CREATE_GROUP_OK, groupEntity)); // 接收到之后修改UI
  }

  /** 删除群成员 REMOVE_CHANGE_MEMBER_TYPE 可能会触发头像的修改 */
  public void reqRemoveGroupMember(int groupId, Set<Integer> removeMemberlist) {
    reqChangeGroupMember(
        groupId, IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_DEL, removeMemberlist);
  }
  /** 新增群成员 ADD_CHANGE_MEMBER_TYPE 可能会触发头像的修改 */
  public void reqAddGroupMember(int groupId, Set<Integer> addMemberlist) {
    reqChangeGroupMember(
        groupId, IMBaseDefine.GroupModifyType.GROUP_MODIFY_TYPE_ADD, addMemberlist);
  }

  private void reqChangeGroupMember(
      int groupId, IMBaseDefine.GroupModifyType groupModifyType, Set<Integer> changeMemberlist) {
    logger.i("group#reqChangeGroupMember, changeGroupMemberType = %s", groupModifyType.toString());

    final int loginId = imLoginManager.getLoginId();
    IMGroup.IMGroupChangeMemberReq groupChangeMemberReq =
        IMGroup.IMGroupChangeMemberReq.newBuilder()
            .setUserId(loginId)
            .setChangeType(groupModifyType)
            .addAllMemberIdList(changeMemberlist)
            .setGroupId(groupId)
            .build();

    int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
    int cid = IMBaseDefine.GroupCmdID.CID_GROUP_CHANGE_MEMBER_REQUEST_VALUE;
    imSocketManager.sendRequest(
        groupChangeMemberReq,
        sid,
        cid,
        new Packetlistener() {
          @Override
          public void onSuccess(Object response) {
            try {
              IMGroup.IMGroupChangeMemberRsp groupChangeMemberRsp =
                  IMGroup.IMGroupChangeMemberRsp.parseFrom((CodedInputStream) response);
              IMGroupManager.instance().onReqChangeGroupMember(groupChangeMemberRsp);
            } catch (IOException e) {
              logger.e("reqChangeGroupMember parse error!");
              triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_FAIL));
            }
          }

          @Override
          public void onFaild() {
            triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_FAIL));
          }

          @Override
          public void onTimeout() {
            triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_TIMEOUT));
          }
        });
  }

  public void onReqChangeGroupMember(IMGroup.IMGroupChangeMemberRsp groupChangeMemberRsp) {
    int resultCode = groupChangeMemberRsp.getResultCode();
    if (0 != resultCode) {
      triggerEvent(new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_FAIL));
      return;
    }

    int groupId = groupChangeMemberRsp.getGroupId();
    List<Integer> changeUserIdList = groupChangeMemberRsp.getChgUserIdListList();
    IMBaseDefine.GroupModifyType groupModifyType = groupChangeMemberRsp.getChangeType();

    GroupEntity groupEntityRet = groupMap.get(groupId);
    groupEntityRet.setlistGroupMemberIds(groupChangeMemberRsp.getCurUserIdListList());
    groupMap.put(groupId, groupEntityRet);
    dbInterface.insertOrUpdateGroup(groupEntityRet);

    GroupEvent groupEvent = new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_SUCCESS);
    groupEvent.setChangeList(changeUserIdList);
    groupEvent.setChangeType(ProtoBuf2JavaBean.getGroupChangeType(groupModifyType));
    groupEvent.setGroupEntity(groupEntityRet);
    triggerEvent(groupEvent);
  }

  /** 屏蔽群消息 IMGroupShieldReq 备注:应为屏蔽之后大部分操作依旧需要客户端做 */
  public void reqShieldGroup(final int groupId, final int shieldType) {
    final GroupEntity entity = groupMap.get(groupId);
    if (entity == null) {
      logger.i("GroupEntity do not exist!");
      return;
    }
    final int loginId = IMLoginManager.instance().getLoginId();
    IMGroup.IMGroupShieldReq shieldReq =
        IMGroup.IMGroupShieldReq.newBuilder()
            .setShieldStatus(shieldType)
            .setGroupId(groupId)
            .setUserId(loginId)
            .build();
    int sid = IMBaseDefine.ServiceID.SID_GROUP_VALUE;
    int cid = IMBaseDefine.GroupCmdID.CID_GROUP_SHIELD_GROUP_REQUEST_VALUE;
    imSocketManager.sendRequest(
        shieldReq,
        sid,
        cid,
        new Packetlistener() {
          @Override
          public void onSuccess(Object response) {
            try {
              IMGroup.IMGroupShieldRsp groupShieldRsp =
                  IMGroup.IMGroupShieldRsp.parseFrom((CodedInputStream) response);
              int resCode = groupShieldRsp.getResultCode();
              if (resCode != 0) {
                triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_FAIL));
                return;
              }
              if (groupShieldRsp.getGroupId() != groupId || groupShieldRsp.getUserId() != loginId) {
                return;
              }
              // 更新DB状态
              entity.setStatus(shieldType);
              dbInterface.insertOrUpdateGroup(entity);
              // 更改未读计数状态
              boolean isFor = shieldType == DBConstant.GROUP_STATUS_SHIELD;
              IMUnreadMsgManager.instance()
                  .setForbidden(
                      EntityChangeEngine.getSessionKey(groupId, DBConstant.SESSION_TYPE_GROUP),
                      isFor);
              triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_OK, entity));

            } catch (IOException e) {
              logger.e("reqChangeGroupMember parse error!");
              triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_FAIL));
            }
          }

          @Override
          public void onFaild() {
            triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_FAIL));
          }

          @Override
          public void onTimeout() {
            triggerEvent(new GroupEvent(GroupEvent.Event.SHIELD_GROUP_TIMEOUT));
          }
        });
  }

  /** 收到群成员发生变更消息 服务端主动发出 DB */
  public void receiveGroupChangeMemberNotify(IMGroup.IMGroupChangeMemberNotify notify) {
    int groupId = notify.getGroupId();
    int changeType = ProtoBuf2JavaBean.getGroupChangeType(notify.getChangeType());
    List<Integer> changeList = notify.getChgUserIdListList();

    List<Integer> curMemberList = notify.getCurUserIdListList();
    if (groupMap.containsKey(groupId)) {
      GroupEntity entity = groupMap.get(groupId);
      entity.setlistGroupMemberIds(curMemberList);
      dbInterface.insertOrUpdateGroup(entity);
      groupMap.put(groupId, entity);

      GroupEvent groupEvent = new GroupEvent(GroupEvent.Event.CHANGE_GROUP_MEMBER_SUCCESS);
      groupEvent.setChangeList(changeList);
      groupEvent.setChangeType(changeType);
      groupEvent.setGroupEntity(entity);
      triggerEvent(groupEvent);
    } else {
      // todo 没有就暂时不管了,只要聊过天都会显示在回话里面
    }
  }

  public List<GroupEntity> getNormalGroupList() {
    List<GroupEntity> normalGroupList = new ArrayList<>();
    for (Entry<Integer, GroupEntity> entry : groupMap.entrySet()) {
      GroupEntity group = entry.getValue();
      if (group == null) {
        continue;
      }
      if (group.getGroupType() == DBConstant.GROUP_TYPE_NORMAL) {
        normalGroupList.add(group);
      }
    }
    return normalGroupList;
  }

  // 该方法只有正式群
  // todo eric efficiency
  public List<GroupEntity> getNormalGroupSortedList() {
    List<GroupEntity> groupList = getNormalGroupList();
    Collections.sort(
        groupList,
        new Comparator<GroupEntity>() {
          @Override
          public int compare(GroupEntity entity1, GroupEntity entity2) {
            if (entity1.getPinyinElement().pinyin == null) {
              PinYin.getPinYin(entity1.getMainName(), entity1.getPinyinElement());
            }
            if (entity2.getPinyinElement().pinyin == null) {
              PinYin.getPinYin(entity2.getMainName(), entity2.getPinyinElement());
            }
            return entity1
                .getPinyinElement()
                .pinyin
                .compareToIgnoreCase(entity2.getPinyinElement().pinyin);
          }
        });

    return groupList;
  }

  public GroupEntity findGroup(int groupId) {
    logger.d("group#findGroup groupId:%s", groupId);
    if (groupMap.containsKey(groupId)) {
      return groupMap.get(groupId);
    }
    return null;
  }

  public List<GroupEntity> getSearchAllGroupList(String key) {
    List<GroupEntity> searchList = new ArrayList<>();
    for (Map.Entry<Integer, GroupEntity> entry : groupMap.entrySet()) {
      GroupEntity groupEntity = entry.getValue();
      if (IMUIHelper.handleGroupSearch(key, groupEntity)) {
        searchList.add(groupEntity);
      }
    }
    return searchList;
  }

  public List<UserEntity> getGroupMembers(int groupId) {
    logger.d("group#getGroupMembers groupId:%s", groupId);

    GroupEntity group = findGroup(groupId);
    if (group == null) {
      logger.e("group#no such group id:%s", groupId);
      return null;
    }
    Set<Integer> userList = group.getlistGroupMemberIds();
    ArrayList<UserEntity> memberList = new ArrayList<UserEntity>();
    for (Integer id : userList) {
      UserEntity contact = IMContactManager.instance().findContact(id);
      if (contact == null) {
        logger.e("group#no such contact id:%s", id);
        continue;
      }
      memberList.add(contact);
    }
    return memberList;
  }

  /** ------set/get 的定义 */
  public Map<Integer, GroupEntity> getGroupMap() {
    return groupMap;
  }

  public boolean isGroupReady() {
    return isGroupReady;
  }
}
  private void showNotification(final UnreadEntity unreadEntity) {
    // todo eric need to set the exact size of the big icon
    // 服务端有些特定的支持 尺寸是不是要调整一下 todo 100*100  下面的就可以不要了
    ImageSize targetSize = new ImageSize(80, 80);
    int peerId = unreadEntity.getPeerId();
    int sessionType = unreadEntity.getSessionType();
    String avatarUrl = "";
    String title = "";
    String content = unreadEntity.getLatestMsgData();
    String unit = ctx.getString(R.string.msg_cnt_unit);
    int totalUnread = unreadEntity.getUnReadCnt();

    if (unreadEntity.getSessionType() == DBConstant.SESSION_TYPE_SINGLE) {
      UserEntity contact = IMContactManager.instance().findContact(peerId);
      if (contact != null) {
        title = contact.getMainName();
        avatarUrl = contact.getAvatar();
      } else {
        title = "User_" + peerId;
        avatarUrl = "";
      }

    } else {
      GroupEntity group = IMGroupManager.instance().findGroup(peerId);
      if (group != null) {
        title = group.getMainName();
        avatarUrl = group.getAvatar();
      } else {
        title = "Group_" + peerId;
        avatarUrl = "";
      }
    }
    // 获取头像
    avatarUrl = IMUIHelper.getRealAvatarUrl(avatarUrl);
    final String ticker = String.format("[%d%s]%s: %s", totalUnread, unit, title, content);
    final int notificationId = getSessionNotificationId(unreadEntity.getSessionKey());
    final Intent intent = new Intent(ctx, MessageActivity.class);
    intent.putExtra(IntentConstant.KEY_SESSION_KEY, unreadEntity.getSessionKey());

    logger.d("notification#notification avatarUrl:%s", avatarUrl);
    final String finalTitle = title;
    ImageLoader.getInstance()
        .loadImage(
            avatarUrl,
            targetSize,
            null,
            new SimpleImageLoadingListener() {

              @Override
              public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                logger.d("notification#icon onLoadComplete");
                // holder.image.setImageBitmap(loadedImage);
                showInNotificationBar(finalTitle, ticker, loadedImage, notificationId, intent);
              }

              @Override
              public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                logger.d("notification#icon onLoadFailed");
                // 服务器支持的格式有哪些
                // todo eric default avatar is too small, need big size(128 * 128)
                Bitmap defaultBitmap =
                    BitmapFactory.decodeResource(
                        ctx.getResources(),
                        IMUIHelper.getDefaultAvatarResId(unreadEntity.getSessionType()));
                showInNotificationBar(finalTitle, ticker, defaultBitmap, notificationId, intent);
              }
            });
  }
 /* End Of BKDR Hash Function */
 public int getSessionNotificationId(String sessionKey) {
   logger.d("notification#getSessionNotificationId sessionTag:%s", sessionKey);
   int hashedNotificationId = (int) hashBKDR(sessionKey);
   logger.d("notification#hashedNotificationId:%d", hashedNotificationId);
   return hashedNotificationId;
 }
/** 伪推送; app退出之后就不会收到推送的信息 通知栏新消息通知 a.每个session 只显示一条 b.每个msg 信息都显示 配置依赖与 configure */
public class IMNotificationManager extends IMManager {

  private Logger logger = Logger.getLogger(IMNotificationManager.class);
  private static IMNotificationManager inst = new IMNotificationManager();

  public static IMNotificationManager instance() {
    return inst;
  }

  private ConfigurationSp configurationSp;

  private IMNotificationManager() {}

  @Override
  public void doOnStart() {
    cancelAllNotifications();
  }

  public void onLoginSuccess() {
    int loginId = IMLoginManager.instance().getLoginId();
    configurationSp = ConfigurationSp.instance(ctx, loginId);
    if (!EventBus.getDefault().isRegistered(inst)) {
      EventBus.getDefault().register(inst);
    }
  }

  public void reset() {
    EventBus.getDefault().unregister(this);
    cancelAllNotifications();
  }

  public void onEventMainThread(UnreadEvent event) {
    switch (event.event) {
      case UNREAD_MSG_RECEIVED:
        UnreadEntity unreadEntity = event.entity;
        handleMsgRecv(unreadEntity);
        break;
    }
  }

  // 屏蔽群,相关的通知全部删除
  public void onEventMainThread(GroupEvent event) {
    GroupEntity gEntity = event.getGroupEntity();
    if (event.getEvent() == GroupEvent.Event.SHIELD_GROUP_OK) {
      if (gEntity == null) {
        return;
      }
      cancelSessionNotifications(gEntity.getSessionKey());
    }
  }

  private void handleMsgRecv(UnreadEntity entity) {
    logger.d("notification#recv unhandled message");
    int peerId = entity.getPeerId();
    int sessionType = entity.getSessionType();
    logger.d("notification#msg no one handled, peerId:%d, sessionType:%d", peerId, sessionType);

    // 判断是否设定了免打扰
    if (entity.isForbidden()) {
      logger.d("notification#GROUP_STATUS_SHIELD");
      return;
    }

    // PC端是否登陆 取消 【暂时先关闭】
    //        if(IMLoginManager.instance().isPcOnline()){
    //            logger.d("notification#isPcOnline");
    //            return;
    //        }

    // 全局开关
    boolean globallyOnOff =
        configurationSp.getCfg(
            SysConstant.SETTING_GLOBAL, ConfigurationSp.CfgDimension.NOTIFICATION);
    if (globallyOnOff) {
      logger.d("notification#shouldGloballyShowNotification is false, return");
      return;
    }

    // 单独的设置
    boolean singleOnOff =
        configurationSp.getCfg(entity.getSessionKey(), ConfigurationSp.CfgDimension.NOTIFICATION);
    if (singleOnOff) {
      logger.d("notification#shouldShowNotificationBySession is false, return");
      return;
    }

    // if the message is a multi login message which send from another terminal,not need notificate
    // to status bar
    // 判断是否是自己的消息
    if (IMLoginManager.instance().getLoginId() != peerId) {
      showNotification(entity);
    }
  }

  public void cancelAllNotifications() {
    logger.d("notification#cancelAllNotifications");
    if (null == ctx) {
      return;
    }
    NotificationManager notifyMgr =
        (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
    if (notifyMgr == null) {
      return;
    }
    notifyMgr.cancelAll();
  }

  /**
   * 在通知栏中删除特定回话的状态
   *
   * @param sessionKey
   */
  public void cancelSessionNotifications(String sessionKey) {
    logger.d("notification#cancelSessionNotifications");
    NotificationManager notifyMgr =
        (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
    if (null == notifyMgr) {
      return;
    }
    int notificationId = getSessionNotificationId(sessionKey);
    notifyMgr.cancel(notificationId);
  }

  private void showNotification(final UnreadEntity unreadEntity) {
    // todo eric need to set the exact size of the big icon
    // 服务端有些特定的支持 尺寸是不是要调整一下 todo 100*100  下面的就可以不要了
    ImageSize targetSize = new ImageSize(80, 80);
    int peerId = unreadEntity.getPeerId();
    int sessionType = unreadEntity.getSessionType();
    String avatarUrl = "";
    String title = "";
    String content = unreadEntity.getLatestMsgData();
    String unit = ctx.getString(R.string.msg_cnt_unit);
    int totalUnread = unreadEntity.getUnReadCnt();

    if (unreadEntity.getSessionType() == DBConstant.SESSION_TYPE_SINGLE) {
      UserEntity contact = IMContactManager.instance().findContact(peerId);
      if (contact != null) {
        title = contact.getMainName();
        avatarUrl = contact.getAvatar();
      } else {
        title = "User_" + peerId;
        avatarUrl = "";
      }

    } else {
      GroupEntity group = IMGroupManager.instance().findGroup(peerId);
      if (group != null) {
        title = group.getMainName();
        avatarUrl = group.getAvatar();
      } else {
        title = "Group_" + peerId;
        avatarUrl = "";
      }
    }
    // 获取头像
    avatarUrl = IMUIHelper.getRealAvatarUrl(avatarUrl);
    final String ticker = String.format("[%d%s]%s: %s", totalUnread, unit, title, content);
    final int notificationId = getSessionNotificationId(unreadEntity.getSessionKey());
    final Intent intent = new Intent(ctx, MessageActivity.class);
    intent.putExtra(IntentConstant.KEY_SESSION_KEY, unreadEntity.getSessionKey());

    logger.d("notification#notification avatarUrl:%s", avatarUrl);
    final String finalTitle = title;
    ImageLoader.getInstance()
        .loadImage(
            avatarUrl,
            targetSize,
            null,
            new SimpleImageLoadingListener() {

              @Override
              public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
                logger.d("notification#icon onLoadComplete");
                // holder.image.setImageBitmap(loadedImage);
                showInNotificationBar(finalTitle, ticker, loadedImage, notificationId, intent);
              }

              @Override
              public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
                logger.d("notification#icon onLoadFailed");
                // 服务器支持的格式有哪些
                // todo eric default avatar is too small, need big size(128 * 128)
                Bitmap defaultBitmap =
                    BitmapFactory.decodeResource(
                        ctx.getResources(),
                        IMUIHelper.getDefaultAvatarResId(unreadEntity.getSessionType()));
                showInNotificationBar(finalTitle, ticker, defaultBitmap, notificationId, intent);
              }
            });
  }

  private void showInNotificationBar(
      String title, String ticker, Bitmap iconBitmap, int notificationId, Intent intent) {
    logger.d("notification#showInNotificationBar title:%s ticker:%s", title, ticker);

    NotificationManager notifyMgr =
        (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
    if (notifyMgr == null) {
      return;
    }

    Builder builder = new NotificationCompat.Builder(ctx);
    builder.setContentTitle(title);
    builder.setContentText(ticker);
    builder.setSmallIcon(R.drawable.tt_small_icon);
    builder.setTicker(ticker);
    builder.setWhen(System.currentTimeMillis());
    builder.setAutoCancel(true);

    // this is the content near the right bottom side
    // builder.setContentInfo("content info");

    if (configurationSp.getCfg(
        SysConstant.SETTING_GLOBAL, ConfigurationSp.CfgDimension.VIBRATION)) {
      // delay 0ms, vibrate 200ms, delay 250ms, vibrate 200ms
      long[] vibrate = {0, 200, 250, 200};
      builder.setVibrate(vibrate);
    } else {
      logger.d("notification#setting is not using vibration");
    }

    // sound
    if (configurationSp.getCfg(SysConstant.SETTING_GLOBAL, ConfigurationSp.CfgDimension.SOUND)) {
      builder.setDefaults(Notification.DEFAULT_SOUND);
    } else {
      logger.d("notification#setting is not using sound");
    }
    if (iconBitmap != null) {
      logger.d("notification#fetch icon from network ok");
      builder.setLargeIcon(iconBitmap);
    } else {
      // do nothint ?
    }
    // if MessageActivity is in the background, the system would bring it to
    // the front
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    PendingIntent pendingIntent =
        PendingIntent.getActivity(ctx, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    builder.setContentIntent(pendingIntent);
    Notification notification = builder.build();
    notifyMgr.notify(notificationId, notification);
  }

  // come from
  // http://www.partow.net/programming/hashfunctions/index.html#BKDRHashFunction
  private long hashBKDR(String str) {
    long seed = 131; // 31 131 1313 13131 131313 etc..
    long hash = 0;

    for (int i = 0; i < str.length(); i++) {
      hash = (hash * seed) + str.charAt(i);
    }
    return hash;
  }

  /* End Of BKDR Hash Function */
  public int getSessionNotificationId(String sessionKey) {
    logger.d("notification#getSessionNotificationId sessionTag:%s", sessionKey);
    int hashedNotificationId = (int) hashBKDR(sessionKey);
    logger.d("notification#hashedNotificationId:%d", hashedNotificationId);
    return hashedNotificationId;
  }
}