• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 Esmertec AG.
3  * Copyright (C) 2007 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.android.im.imps;
19 
20 import java.util.ArrayList;
21 
22 import com.android.im.engine.Address;
23 import com.android.im.engine.ChatGroup;
24 import com.android.im.engine.ChatGroupManager;
25 import com.android.im.engine.Contact;
26 import com.android.im.engine.GroupListener;
27 import com.android.im.engine.GroupMemberListener;
28 import com.android.im.engine.Invitation;
29 
30 /**
31  * The implementation of ChatGroupManager with IMPS protocol.
32  */
33 public class ImpsChatGroupManager extends ChatGroupManager implements
34         ServerTransactionListener {
35     private ImpsConnection mConnection;
36     private ImpsTransactionManager mTransactionManager;
37 
ImpsChatGroupManager(ImpsConnection connection)38     ImpsChatGroupManager(ImpsConnection connection) {
39         mConnection = connection;
40 
41         mTransactionManager = connection.getTransactionManager();
42         mTransactionManager.setTransactionListener(ImpsTags.GroupChangeNotice, this);
43         mTransactionManager.setTransactionListener(ImpsTags.LeaveGroup_Response, this);
44         mTransactionManager.setTransactionListener(ImpsTags.InviteUser_Request, this);
45         mTransactionManager.setTransactionListener(ImpsTags.Invite_Response, this);
46     }
47 
48     @Override
addGroupMemberAsync(final ChatGroup group, final Contact contact)49     protected void addGroupMemberAsync(final ChatGroup group, final Contact contact){
50         Primitive request = buildAddGroupMemberRequest(group, contact);
51 
52         AsyncTransaction tx = new AsyncTransaction(mTransactionManager) {
53             @Override
54             public void onResponseError(ImpsErrorInfo error) {
55                 notifyGroupMemberError(group, error);
56             }
57 
58             @Override
59             public void onResponseOk(Primitive response) {
60                 notifyMemberJoined(group, contact);
61             }
62         };
63         tx.sendRequest(request);
64     }
65 
66     @Override
createChatGroupAsync(final String name)67     public void createChatGroupAsync(final String name) {
68         final ImpsAddress loginUserAddress = mConnection.getSession()
69                 .getLoginUserAddress();
70         final ImpsAddress groupAddress = new ImpsGroupAddress(loginUserAddress, name);
71 
72         Primitive primitive = buildCreateGroupRequest(name, groupAddress);
73 
74         AsyncTransaction tx = new AsyncTransaction(mTransactionManager) {
75             @Override
76             public void onResponseError(ImpsErrorInfo error) {
77                 notifyGroupError(GroupListener.ERROR_CREATING_GROUP, name, error);
78             }
79 
80             @Override
81             public void onResponseOk(Primitive response) {
82                 // The current user is joined into the group automatically.
83                 ArrayList<Contact> members = new ArrayList<Contact>();
84                 members.add(new Contact(loginUserAddress, loginUserAddress
85                         .getUser()));
86 
87                 ChatGroup group = new ChatGroup(groupAddress, name, members,
88                         ImpsChatGroupManager.this);
89                 notifyGroupCreated(group);
90             }
91         };
92         tx.sendRequest(primitive);
93     }
94 
95     @Override
deleteChatGroupAsync(final ChatGroup group)96     public void deleteChatGroupAsync(final ChatGroup group) {
97         Primitive request = new Primitive(ImpsTags.DeleteGroup_Request);
98         request.addElement(ImpsTags.GroupID, group.getAddress().getFullName());
99 
100         AsyncTransaction tx = new AsyncTransaction(mTransactionManager) {
101             @Override
102             public void onResponseError(ImpsErrorInfo error) {
103                 notifyGroupError(GroupListener.ERROR_DELETING_GROUP,
104                     group.getName(), error);
105             }
106 
107             @Override
108             public void onResponseOk(Primitive response) {
109                 notifyGroupDeleted(group);
110             }
111         };
112         tx.sendRequest(request);
113     }
114 
115     @Override
inviteUserAsync(final ChatGroup group, Contact contact)116     public void inviteUserAsync(final ChatGroup group, Contact contact) {
117         Primitive request = buildInviteUserRequest(group, contact);
118 
119         AsyncTransaction tx = new AsyncTransaction(mTransactionManager){
120             @Override
121             public void onResponseError(ImpsErrorInfo error) {
122                 notifyGroupMemberError(group, error);
123             }
124 
125             @Override
126             public void onResponseOk(Primitive response) {
127                 //Do nothing
128             }
129         };
130         tx.sendRequest(request);
131     }
132 
133     @Override
acceptInvitationAsync(Invitation invitation)134     public void acceptInvitationAsync(Invitation invitation){
135         joinChatGroupAsync(invitation.getGroupAddress());
136         sendInvitationResposne(invitation, true);
137     }
138 
139     @Override
rejectInvitationAsync(Invitation invitation)140     public void rejectInvitationAsync(Invitation invitation) {
141         sendInvitationResposne(invitation, false);
142     }
143 
sendInvitationResposne(Invitation invitation, boolean accept)144     private void sendInvitationResposne(Invitation invitation, boolean accept) {
145         Primitive response = new Primitive(ImpsTags.InviteUser_Response);
146         response.addElement(ImpsTags.InviteID, invitation.getInviteID());
147         response.addElement(ImpsTags.Acceptance, ImpsUtils.toImpsBool(accept));
148         ImpsAddress sender = (ImpsAddress) invitation.getSender();
149         response.addElement(sender.toPrimitiveElement());
150         AsyncTransaction tx = new AsyncTransaction(mTransactionManager){
151             @Override
152             public void onResponseError(ImpsErrorInfo error) {
153                 // Ignore
154             }
155             @Override
156             public void onResponseOk(Primitive res) {
157                 // Ignore
158             }
159         };
160         tx.sendRequest(response);
161     }
162 
163     @Override
joinChatGroupAsync(final Address address)164     public void joinChatGroupAsync(final Address address) {
165         Primitive request = buildJoinGroupRequest(address);
166 
167         AsyncTransaction tx = new AsyncTransaction(mTransactionManager) {
168             @Override
169             public void onResponseError(ImpsErrorInfo error) {
170                 notifyGroupError(GroupListener.ERROR_JOINING_IN_GROUP,
171                     address.getScreenName(), error);
172             }
173 
174             @Override
175             public void onResponseOk(Primitive response) {
176                 ArrayList<Contact> members = new ArrayList<Contact>();
177                 // FIXME: UserMapList is a child of Joined in version 1.3
178                 PrimitiveElement userMapping = response
179                         .getElement(ImpsTags.UserMapList);
180                 extractUserMapList(userMapping, members);
181 
182                 ChatGroup group = new ChatGroup(address, address
183                         .getScreenName(), members, ImpsChatGroupManager.this);
184                 notifyJoinedGroup(group);
185             }
186         };
187         tx.sendRequest(request);
188     }
189 
190     @Override
leaveChatGroupAsync(final ChatGroup group)191     public void leaveChatGroupAsync(final ChatGroup group) {
192         Primitive leaveRequest = buildLeaveGroupRequest(group);
193         AsyncTransaction tx = new AsyncTransaction(mTransactionManager) {
194             @Override
195             public void onResponseError(ImpsErrorInfo error) {
196                 notifyGroupError(GroupListener.ERROR_LEAVING_GROUP,
197                     group.getName(), error);
198             }
199 
200             @Override
201             public void onResponseOk(Primitive response) {
202                 notifyLeftGroup(group);
203             }
204         };
205         tx.sendRequest(leaveRequest);
206     }
207 
208     @Override
removeGroupMemberAsync(final ChatGroup group, final Contact contact)209     protected void removeGroupMemberAsync(final ChatGroup group, final Contact contact) {
210         Primitive request = buildRemoveGroupMemberRequest(group, contact);
211 
212         AsyncTransaction tx = new AsyncTransaction(mTransactionManager) {
213             @Override
214             public void onResponseError(ImpsErrorInfo error) {
215                 notifyGroupMemberError(group, error);
216             }
217 
218             @Override
219             public void onResponseOk(Primitive response) {
220                 notifyMemberLeft(group, contact);
221             }
222         };
223         tx.sendRequest(request);
224     }
225 
226     /**
227      * Loads the members of a ChatGroup asynchronously. This method will create
228      * a ChatGroup and return immediately. After the members are fetched from
229      * the server,
230      * {@link GroupMemberListener#onMemberJoined(ChatGroup, Contact)}} will be
231      * called.
232      *
233      * @param address
234      */
loadGroupMembersAsync(ImpsGroupAddress address)235     ChatGroup loadGroupMembersAsync(ImpsGroupAddress address) {
236         //FIXME: NowIMP Server doesn't support this primitive.
237 //        Primitive request = new Primitive(ImpsTags.GetJoinedUsers_Request);
238 //        request.addElement(ImpsTags.GroupID, address.getFullName());
239 //        Primitive response = mConnection.sendRequest(request);
240 //        ImpsUtils.checkResult(response);
241 //
242 //        ChatGroup group = new ChatGroup(address, address.getScreenName(), this);
243         throw new RuntimeException("Not implemented yet");
244     }
245 
notifyServerTransaction(ServerTransaction tx)246     public void notifyServerTransaction(ServerTransaction tx) {
247         final Primitive primitive = tx.getRequest();
248         String type = primitive.getType();
249         if (ImpsTags.GroupChangeNotice.equals(type)) {
250             tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE);
251             handleGroupChange(primitive);
252         } else if (ImpsTags.InviteUser_Request.equals(type)) {
253             tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE);
254 
255             String inviteType = primitive.getElementContents(ImpsTags.InviteType);
256             // We only handle Group invitation right now.
257             if (ImpsConstants.GROUP_INVITATION.equals(inviteType)) {
258                 handleInvitation(primitive);
259             }
260         } else if (ImpsTags.LeaveGroup_Response.equals(type)) {
261             tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE);
262             String groupId = primitive.getElementContents(ImpsTags.GroupID);
263             ChatGroup group = mGroups.get(new ImpsGroupAddress(groupId));
264             if(group != null) {
265                 notifyLeftGroup(group);
266             } else {
267                 ImpsLog.log("Leave unknown group:" + groupId);
268             }
269         } else if (ImpsTags.Invite_Response.equals(type)) {
270             tx.sendStatusResponse(ImpsConstants.SUCCESS_CODE);
271             //TODO: notify the user?
272         }
273     }
274 
handleGroupChange(final Primitive primitive)275     void handleGroupChange(final Primitive primitive) {
276         String groupId = primitive.getElementContents(ImpsTags.GroupID);
277         ImpsGroupAddress address = new ImpsGroupAddress(groupId);
278 
279         ArrayList<Contact> joined = new ArrayList<Contact>();
280         PrimitiveElement joinedElem = primitive.getElement(ImpsTags.Joined);
281         if (joinedElem != null) {
282             extractUserMapList(joinedElem.getFirstChild(), joined);
283         }
284         ArrayList<Contact> left = new ArrayList<Contact>();
285         PrimitiveElement leftElem = primitive.getElement(ImpsTags.Left);
286         if (leftElem != null) {
287             extractUserMapList(leftElem.getFirstChild(), left);
288         }
289 
290         notifyGroupChanged(address, joined, left);
291     }
292 
handleInvitation(final Primitive primitive)293     void handleInvitation(final Primitive primitive) {
294         String inviteId = primitive.getElementContents(ImpsTags.InviteID);
295         PrimitiveElement sender = primitive.getElement(ImpsTags.Sender);
296         ImpsAddress senderAddress = ImpsAddress.fromPrimitiveElement(sender
297                 .getFirstChild());
298         String groupId = primitive.getElementContents(ImpsTags.GroupID);
299         Address groupAddress = new ImpsGroupAddress(groupId);
300         String inviteNote = primitive.getElementContents(ImpsTags.InviteNote);
301 
302         Invitation invitation = new Invitation(inviteId, groupAddress,
303                 senderAddress, inviteNote);
304         notifyGroupInvitation(invitation);
305     }
306 
buildAddGroupMemberRequest(final ChatGroup group, final Contact contact)307     private Primitive buildAddGroupMemberRequest(final ChatGroup group, final Contact contact) {
308         Primitive request = new Primitive(ImpsTags.AddGroupMembers_Request);
309         request.addElement(ImpsTags.GroupID, group.getAddress().getFullName());
310 
311         // FIXME: It's UserIDList in 1.3
312         PrimitiveElement userList = request.addElement(ImpsTags.UserList);
313         PrimitiveElement user = userList.addChild(ImpsTags.User);
314         user.addChild(ImpsTags.UserID, contact.getAddress().getFullName());
315         return request;
316     }
317 
buildCreateGroupRequest(String name, ImpsAddress groupAddress)318     private Primitive buildCreateGroupRequest(String name, ImpsAddress groupAddress) {
319         Primitive primitive = new Primitive(ImpsTags.CreateGroup_Request);
320         primitive.addElement(ImpsTags.GroupID, groupAddress.getFullName());
321         PrimitiveElement propertiesElem = primitive.addElement(ImpsTags.GroupProperties);
322         propertiesElem.addPropertyChild(ImpsTags.Name, name);
323         propertiesElem.addPropertyChild(ImpsTags.Accesstype, ImpsConstants.Open);
324         propertiesElem.addPropertyChild(ImpsTags.PrivateMessaging, false);
325         propertiesElem.addPropertyChild(ImpsTags.Searchable, false);
326         propertiesElem.addPropertyChild(ImpsTags.AutoDelete, true);
327 
328         // TODO: welcome note?
329         primitive.addElement(ImpsTags.JoinGroup, true);
330 
331         PrimitiveElement screenName = primitive.addElement(ImpsTags.ScreenName);
332         screenName.addChild(ImpsTags.SName, mConnection.getLoginUserName());
333         screenName.addChild(ImpsTags.GroupID, groupAddress.getFullName());
334 
335         primitive.addElement(ImpsTags.SubscribeNotification, true);
336 
337         return primitive;
338     }
339 
buildInviteUserRequest(ChatGroup group, Contact contact)340     private Primitive buildInviteUserRequest(ChatGroup group, Contact contact) {
341         String inviteId = nextInviteID();
342         Primitive request = new Primitive(ImpsTags.Invite_Request);
343         request.addElement(ImpsTags.InviteID, inviteId);
344         request.addElement(ImpsTags.InviteType, ImpsConstants.GROUP_INVITATION);
345 
346         // FIXME: <Sender> is only required in IMPS1.3
347         // ImpsGroupAddress groupAddress = (ImpsGroupAddress)group.getAddress();
348         // groupAddress.setScreenName(mConnection.getLoginUser());
349         // request.addElement(ImpsTags.Sender).addChild(groupAddress.toPrimitiveElement());
350 
351         request.addElement(ImpsTags.Recipient).addChild(
352                 ((ImpsAddress)contact.getAddress()).toPrimitiveElement());
353         request.addElement(ImpsTags.GroupID, group.getAddress().getFullName());
354 
355         // FIXME: <ScreenName> is only needed in IMPS1.2
356         PrimitiveElement screenName = request.addElement(ImpsTags.ScreenName);
357         screenName.addChild(ImpsTags.SName, mConnection.getLoginUserName());
358         screenName.addChild(ImpsTags.GroupID, group.getAddress().getFullName());
359         return request;
360     }
361 
buildJoinGroupRequest(Address address)362     private Primitive buildJoinGroupRequest(Address address) {
363         Primitive request = new Primitive(ImpsTags.JoinGroup_Request);
364         request.addElement(ImpsTags.GroupID, address.getFullName());
365         PrimitiveElement screenName = request.addElement(ImpsTags.ScreenName);
366         screenName.addChild(ImpsTags.SName, mConnection.getLoginUserName());
367         screenName.addChild(ImpsTags.GroupID, address.getFullName());
368 
369         request.addElement(ImpsTags.JoinedRequest, true);
370         request.addElement(ImpsTags.SubscribeNotification, true);
371         return request;
372     }
373 
buildLeaveGroupRequest(ChatGroup group)374     private Primitive buildLeaveGroupRequest(ChatGroup group) {
375         Primitive leaveRequest = new Primitive(ImpsTags.LeaveGroup_Request);
376         leaveRequest.addElement(ImpsTags.GroupID, group.getAddress().getFullName());
377         return leaveRequest;
378     }
379 
buildRemoveGroupMemberRequest(ChatGroup group, Contact contact)380     private Primitive buildRemoveGroupMemberRequest(ChatGroup group, Contact contact) {
381         Primitive request = new Primitive(ImpsTags.RemoveGroupMembers_Request);
382         request.addElement(ImpsTags.GroupID, group.getAddress().getFullName());
383 
384         // FIXME: It's UserIDList in 1.3
385         PrimitiveElement userList = request.addElement(ImpsTags.UserList);
386         PrimitiveElement user = userList.addChild(ImpsTags.User);
387         user.addChild(ImpsTags.UserID, contact.getAddress().getFullName());
388         return request;
389     }
390 
extractUserMapList(PrimitiveElement userMapList, ArrayList<Contact> list)391     private void extractUserMapList(PrimitiveElement userMapList,
392             ArrayList<Contact> list) {
393         // FIXME: UserMapping is the child of UserMapList in version 1.3
394         PrimitiveElement userMapping = userMapList;
395 
396         if (userMapping != null) {
397             for (PrimitiveElement mapping : userMapping.getChildren()) {
398                 String name = mapping.getChildContents(ImpsTags.SName);
399                 String id = mapping.getChildContents(ImpsTags.UserID);
400                 if (id == null) {
401                     id = name;
402                 }
403                 list.add((Contact)(new ImpsUserAddress(id)).getEntity(mConnection));
404             }
405         }
406     }
407     private static int sInviteID = 0;
408 
nextInviteID()409     private synchronized String nextInviteID() {
410         return "invite" + System.currentTimeMillis() + (sInviteID++);
411     }
412 }
413