| /* |
| * Copyright (C) 2007 Esmertec AG. |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.im.imps; |
| |
| import java.util.ArrayList; |
| |
| import com.android.im.engine.Address; |
| import com.android.im.engine.ChatGroup; |
| import com.android.im.engine.ChatGroupManager; |
| import com.android.im.engine.Contact; |
| import com.android.im.engine.GroupListener; |
| import com.android.im.engine.GroupMemberListener; |
| import com.android.im.engine.Invitation; |
| |
| /** |
| * The implementation of ChatGroupManager with IMPS protocol. |
| */ |
| public class ImpsChatGroupManager extends ChatGroupManager implements |
| ServerTransactionListener { |
| private ImpsConnection mConnection; |
| private ImpsTransactionManager mTransactionManager; |
| |
| ImpsChatGroupManager(ImpsConnection connection) { |
| mConnection = connection; |
| |
| mTransactionManager = connection.getTransactionManager(); |
| mTransactionManager.setTransactionListener(ImpsTags.GroupChangeNotice, this); |
| mTransactionManager.setTransactionListener(ImpsTags.LeaveGroup_Response, this); |
| mTransactionManager.setTransactionListener(ImpsTags.InviteUser_Request, this); |
| mTransactionManager.setTransactionListener(ImpsTags.Invite_Response, this); |
| } |
| |
| @Override |
| protected void addGroupMemberAsync(final ChatGroup group, final Contact contact){ |
| Primitive request = buildAddGroupMemberRequest(group, contact); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyGroupMemberError(group, error); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| notifyMemberJoined(group, contact); |
| } |
| }; |
| tx.sendRequest(request); |
| } |
| |
| @Override |
| public void createChatGroupAsync(final String name) { |
| final ImpsAddress loginUserAddress = mConnection.getSession() |
| .getLoginUserAddress(); |
| final ImpsAddress groupAddress = new ImpsGroupAddress(loginUserAddress, name); |
| |
| Primitive primitive = buildCreateGroupRequest(name, groupAddress); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyGroupError(GroupListener.ERROR_CREATING_GROUP, name, error); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| // The current user is joined into the group automatically. |
| ArrayList<Contact> members = new ArrayList<Contact>(); |
| members.add(new Contact(loginUserAddress, loginUserAddress |
| .getUser())); |
| |
| ChatGroup group = new ChatGroup(groupAddress, name, members, |
| ImpsChatGroupManager.this); |
| notifyGroupCreated(group); |
| } |
| }; |
| tx.sendRequest(primitive); |
| } |
| |
| @Override |
| public void deleteChatGroupAsync(final ChatGroup group) { |
| Primitive request = new Primitive(ImpsTags.DeleteGroup_Request); |
| request.addElement(ImpsTags.GroupID, group.getAddress().getFullName()); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyGroupError(GroupListener.ERROR_DELETING_GROUP, |
| group.getName(), error); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| notifyGroupDeleted(group); |
| } |
| }; |
| tx.sendRequest(request); |
| } |
| |
| @Override |
| public void inviteUserAsync(final ChatGroup group, Contact contact) { |
| Primitive request = buildInviteUserRequest(group, contact); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager){ |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyGroupMemberError(group, error); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| //Do nothing |
| } |
| }; |
| tx.sendRequest(request); |
| } |
| |
| @Override |
| public void acceptInvitationAsync(Invitation invitation){ |
| joinChatGroupAsync(invitation.getGroupAddress()); |
| sendInvitationResposne(invitation, true); |
| } |
| |
| @Override |
| public void rejectInvitationAsync(Invitation invitation) { |
| sendInvitationResposne(invitation, false); |
| } |
| |
| private void sendInvitationResposne(Invitation invitation, boolean accept) { |
| Primitive response = new Primitive(ImpsTags.InviteUser_Response); |
| response.addElement(ImpsTags.InviteID, invitation.getInviteID()); |
| response.addElement(ImpsTags.Acceptance, ImpsUtils.toImpsBool(accept)); |
| ImpsAddress sender = (ImpsAddress) invitation.getSender(); |
| response.addElement(sender.toPrimitiveElement()); |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager){ |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| // Ignore |
| } |
| @Override |
| public void onResponseOk(Primitive res) { |
| // Ignore |
| } |
| }; |
| tx.sendRequest(response); |
| } |
| |
| @Override |
| public void joinChatGroupAsync(final Address address) { |
| Primitive request = buildJoinGroupRequest(address); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyGroupError(GroupListener.ERROR_JOINING_IN_GROUP, |
| address.getScreenName(), error); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| ArrayList<Contact> members = new ArrayList<Contact>(); |
| // FIXME: UserMapList is a child of Joined in version 1.3 |
| PrimitiveElement userMapping = response |
| .getElement(ImpsTags.UserMapList); |
| extractUserMapList(userMapping, members); |
| |
| ChatGroup group = new ChatGroup(address, address |
| .getScreenName(), members, ImpsChatGroupManager.this); |
| notifyJoinedGroup(group); |
| } |
| }; |
| tx.sendRequest(request); |
| } |
| |
| @Override |
| public void leaveChatGroupAsync(final ChatGroup group) { |
| Primitive leaveRequest = buildLeaveGroupRequest(group); |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyGroupError(GroupListener.ERROR_LEAVING_GROUP, |
| group.getName(), error); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| notifyLeftGroup(group); |
| } |
| }; |
| tx.sendRequest(leaveRequest); |
| } |
| |
| @Override |
| protected void removeGroupMemberAsync(final ChatGroup group, final Contact contact) { |
| Primitive request = buildRemoveGroupMemberRequest(group, contact); |
| |
| AsyncTransaction tx = new AsyncTransaction(mTransactionManager) { |
| @Override |
| public void onResponseError(ImpsErrorInfo error) { |
| notifyGroupMemberError(group, error); |
| } |
| |
| @Override |
| public void onResponseOk(Primitive response) { |
| notifyMemberLeft(group, contact); |
| } |
| }; |
| tx.sendRequest(request); |
| } |
| |
| /** |
| * Loads the members of a ChatGroup asynchronously. This method will create |
| * a ChatGroup and return immediately. After the members are fetched from |
| * the server, |
| * {@link GroupMemberListener#onMemberJoined(ChatGroup, Contact)}} will be |
| * called. |
| * |
| * @param address |
| */ |
| ChatGroup loadGroupMembersAsync(ImpsGroupAddress address) { |
| //FIXME: NowIMP Server doesn't support this primitive. |
| // Primitive request = new Primitive(ImpsTags.GetJoinedUsers_Request); |
| // request.addElement(ImpsTags.GroupID, address.getFullName()); |
| // Primitive response = mConnection.sendRequest(request); |
| // ImpsUtils.checkResult(response); |
| // |
| // ChatGroup group = new ChatGroup(address, address.getScreenName(), this); |
| throw new RuntimeException("Not implemented yet"); |
| } |
| |
| public void notifyServerTransaction(ServerTransaction tx) { |
| final Primitive primitive = tx.getRequest(); |
| String type = primitive.getType(); |
| if (ImpsTags.GroupChangeNotice.equals(type)) { |
| tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE); |
| handleGroupChange(primitive); |
| } else if (ImpsTags.InviteUser_Request.equals(type)) { |
| tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE); |
| |
| String inviteType = primitive.getElementContents(ImpsTags.InviteType); |
| // We only handle Group invitation right now. |
| if (ImpsConstants.GROUP_INVITATION.equals(inviteType)) { |
| handleInvitation(primitive); |
| } |
| } else if (ImpsTags.LeaveGroup_Response.equals(type)) { |
| tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE); |
| String groupId = primitive.getElementContents(ImpsTags.GroupID); |
| ChatGroup group = mGroups.get(new ImpsGroupAddress(groupId)); |
| if(group != null) { |
| notifyLeftGroup(group); |
| } else { |
| ImpsLog.log("Leave unknown group:" + groupId); |
| } |
| } else if (ImpsTags.Invite_Response.equals(type)) { |
| tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE); |
| //TODO: notify the user? |
| } |
| } |
| |
| void handleGroupChange(final Primitive primitive) { |
| String groupId = primitive.getElementContents(ImpsTags.GroupID); |
| ImpsGroupAddress address = new ImpsGroupAddress(groupId); |
| |
| ArrayList<Contact> joined = new ArrayList<Contact>(); |
| PrimitiveElement joinedElem = primitive.getElement(ImpsTags.Joined); |
| if (joinedElem != null) { |
| extractUserMapList(joinedElem.getFirstChild(), joined); |
| } |
| ArrayList<Contact> left = new ArrayList<Contact>(); |
| PrimitiveElement leftElem = primitive.getElement(ImpsTags.Left); |
| if (leftElem != null) { |
| extractUserMapList(leftElem.getFirstChild(), left); |
| } |
| |
| notifyGroupChanged(address, joined, left); |
| } |
| |
| void handleInvitation(final Primitive primitive) { |
| String inviteId = primitive.getElementContents(ImpsTags.InviteID); |
| PrimitiveElement sender = primitive.getElement(ImpsTags.Sender); |
| ImpsAddress senderAddress = ImpsAddress.fromPrimitiveElement(sender |
| .getFirstChild()); |
| String groupId = primitive.getElementContents(ImpsTags.GroupID); |
| Address groupAddress = new ImpsGroupAddress(groupId); |
| String inviteNote = primitive.getElementContents(ImpsTags.InviteNote); |
| |
| Invitation invitation = new Invitation(inviteId, groupAddress, |
| senderAddress, inviteNote); |
| notifyGroupInvitation(invitation); |
| } |
| |
| private Primitive buildAddGroupMemberRequest(final ChatGroup group, final Contact contact) { |
| Primitive request = new Primitive(ImpsTags.AddGroupMembers_Request); |
| request.addElement(ImpsTags.GroupID, group.getAddress().getFullName()); |
| |
| // FIXME: It's UserIDList in 1.3 |
| PrimitiveElement userList = request.addElement(ImpsTags.UserList); |
| PrimitiveElement user = userList.addChild(ImpsTags.User); |
| user.addChild(ImpsTags.UserID, contact.getAddress().getFullName()); |
| return request; |
| } |
| |
| private Primitive buildCreateGroupRequest(String name, ImpsAddress groupAddress) { |
| Primitive primitive = new Primitive(ImpsTags.CreateGroup_Request); |
| primitive.addElement(ImpsTags.GroupID, groupAddress.getFullName()); |
| PrimitiveElement propertiesElem = primitive.addElement(ImpsTags.GroupProperties); |
| propertiesElem.addPropertyChild(ImpsTags.Name, name); |
| propertiesElem.addPropertyChild(ImpsTags.Accesstype, ImpsConstants.Open); |
| propertiesElem.addPropertyChild(ImpsTags.PrivateMessaging, false); |
| propertiesElem.addPropertyChild(ImpsTags.Searchable, false); |
| propertiesElem.addPropertyChild(ImpsTags.AutoDelete, true); |
| |
| // TODO: welcome note? |
| primitive.addElement(ImpsTags.JoinGroup, true); |
| |
| PrimitiveElement screenName = primitive.addElement(ImpsTags.ScreenName); |
| screenName.addChild(ImpsTags.SName, mConnection.getLoginUserName()); |
| screenName.addChild(ImpsTags.GroupID, groupAddress.getFullName()); |
| |
| primitive.addElement(ImpsTags.SubscribeNotification, true); |
| |
| return primitive; |
| } |
| |
| private Primitive buildInviteUserRequest(ChatGroup group, Contact contact) { |
| String inviteId = nextInviteID(); |
| Primitive request = new Primitive(ImpsTags.Invite_Request); |
| request.addElement(ImpsTags.InviteID, inviteId); |
| request.addElement(ImpsTags.InviteType, ImpsConstants.GROUP_INVITATION); |
| |
| // FIXME: <Sender> is only required in IMPS1.3 |
| // ImpsGroupAddress groupAddress = (ImpsGroupAddress)group.getAddress(); |
| // groupAddress.setScreenName(mConnection.getLoginUser()); |
| // request.addElement(ImpsTags.Sender).addChild(groupAddress.toPrimitiveElement()); |
| |
| request.addElement(ImpsTags.Recipient).addChild( |
| ((ImpsAddress)contact.getAddress()).toPrimitiveElement()); |
| request.addElement(ImpsTags.GroupID, group.getAddress().getFullName()); |
| |
| // FIXME: <ScreenName> is only needed in IMPS1.2 |
| PrimitiveElement screenName = request.addElement(ImpsTags.ScreenName); |
| screenName.addChild(ImpsTags.SName, mConnection.getLoginUserName()); |
| screenName.addChild(ImpsTags.GroupID, group.getAddress().getFullName()); |
| return request; |
| } |
| |
| private Primitive buildJoinGroupRequest(Address address) { |
| Primitive request = new Primitive(ImpsTags.JoinGroup_Request); |
| request.addElement(ImpsTags.GroupID, address.getFullName()); |
| PrimitiveElement screenName = request.addElement(ImpsTags.ScreenName); |
| screenName.addChild(ImpsTags.SName, mConnection.getLoginUserName()); |
| screenName.addChild(ImpsTags.GroupID, address.getFullName()); |
| |
| request.addElement(ImpsTags.JoinedRequest, true); |
| request.addElement(ImpsTags.SubscribeNotification, true); |
| return request; |
| } |
| |
| private Primitive buildLeaveGroupRequest(ChatGroup group) { |
| Primitive leaveRequest = new Primitive(ImpsTags.LeaveGroup_Request); |
| leaveRequest.addElement(ImpsTags.GroupID, group.getAddress().getFullName()); |
| return leaveRequest; |
| } |
| |
| private Primitive buildRemoveGroupMemberRequest(ChatGroup group, Contact contact) { |
| Primitive request = new Primitive(ImpsTags.RemoveGroupMembers_Request); |
| request.addElement(ImpsTags.GroupID, group.getAddress().getFullName()); |
| |
| // FIXME: It's UserIDList in 1.3 |
| PrimitiveElement userList = request.addElement(ImpsTags.UserList); |
| PrimitiveElement user = userList.addChild(ImpsTags.User); |
| user.addChild(ImpsTags.UserID, contact.getAddress().getFullName()); |
| return request; |
| } |
| |
| private void extractUserMapList(PrimitiveElement userMapList, |
| ArrayList<Contact> list) { |
| // FIXME: UserMapping is the child of UserMapList in version 1.3 |
| PrimitiveElement userMapping = userMapList; |
| |
| if (userMapping != null) { |
| for (PrimitiveElement mapping : userMapping.getChildren()) { |
| String name = mapping.getChildContents(ImpsTags.SName); |
| String id = mapping.getChildContents(ImpsTags.UserID); |
| if (id == null) { |
| id = name; |
| } |
| list.add((Contact)(new ImpsUserAddress(id)).getEntity(mConnection)); |
| } |
| } |
| } |
| private static int sInviteID = 0; |
| |
| private synchronized String nextInviteID() { |
| return "invite" + System.currentTimeMillis() + (sInviteID++); |
| } |
| } |