use of org.matrix.androidsdk.rest.model.MatrixError in project matrix-android-sdk by matrix-org.
the class CryptoTestHelper method createAccountAndSync.
/**
* Create an account and a dedicated session
* @param context the context
* @param userName the account username
* @param password the password
* @param startSession true to perform an initial sync
* @throws Exception an exception if the account creation failed
*/
public static MXSession createAccountAndSync(Context context, String userName, String password, boolean startSession) throws Exception {
Uri uri = Uri.parse(TESTS_HOME_SERVER_URL);
HomeServerConnectionConfig hs = new HomeServerConnectionConfig(uri);
LoginRestClient loginRestClient = new LoginRestClient(hs);
final HashMap<String, Object> params = new HashMap<>();
RegistrationParams registrationParams = new RegistrationParams();
mLock = new CountDownLatch(1);
// get the registration session id
loginRestClient.register(registrationParams, new ApiCallback<Credentials>() {
@Override
public void onSuccess(Credentials credentials) {
mLock.countDown();
}
@Override
public void onNetworkError(Exception e) {
mLock.countDown();
}
@Override
public void onMatrixError(MatrixError e) {
// detect if a parameter is expected
RegistrationFlowResponse registrationFlowResponse = null;
// when a response is not completed the server returns an error message
if ((null != e.mStatus) && (e.mStatus == 401)) {
try {
registrationFlowResponse = JsonUtils.toRegistrationFlowResponse(e.mErrorBodyAsString);
} catch (Exception castExcept) {
}
}
// check if the server response can be casted
if (null != registrationFlowResponse) {
params.put("session", registrationFlowResponse.session);
}
mLock.countDown();
}
@Override
public void onUnexpectedError(Exception e) {
mLock.countDown();
}
});
mLock.await(10000, TimeUnit.MILLISECONDS);
String session = (String) params.get("session");
assertTrue(null != session);
registrationParams.username = userName;
registrationParams.password = password;
HashMap<String, Object> authParams = new HashMap<>();
authParams.put("session", session);
authParams.put("type", LoginRestClient.LOGIN_FLOW_TYPE_DUMMY);
registrationParams.auth = authParams;
mLock = new CountDownLatch(1);
loginRestClient.register(registrationParams, new ApiCallback<Credentials>() {
@Override
public void onSuccess(Credentials credentials) {
params.put("credentials", credentials);
mLock.countDown();
}
@Override
public void onNetworkError(Exception e) {
mLock.countDown();
}
@Override
public void onMatrixError(MatrixError e) {
mLock.countDown();
}
@Override
public void onUnexpectedError(Exception e) {
mLock.countDown();
}
});
mLock.await(10000, TimeUnit.MILLISECONDS);
Credentials credentials = (Credentials) params.get("credentials");
assertTrue(null != credentials);
hs.setCredentials(credentials);
IMXStore store = new MXFileStore(hs, context);
MXSession mxSession = new MXSession(hs, new MXDataHandler(store, credentials), context);
if (!startSession) {
return mxSession;
}
mxSession.getDataHandler().getStore().open();
mxSession.startEventStream(null);
mLock = new CountDownLatch(1);
mxSession.getDataHandler().addListener(new MXEventListener() {
@Override
public void onInitialSyncComplete(String toToken) {
params.put("isInit", true);
mLock.countDown();
}
});
mLock.await(100000, TimeUnit.MILLISECONDS);
assertTrue(params.containsKey("isInit"));
return mxSession;
}
use of org.matrix.androidsdk.rest.model.MatrixError in project matrix-android-sdk by matrix-org.
the class MXDataHandler method manageResponse.
/**
* Manage the sync response in the UI thread.
*
* @param syncResponse the syncResponse to manage.
* @param fromToken the start sync token
* @param isCatchingUp true when there is a pending catch-up
*/
private void manageResponse(final SyncResponse syncResponse, final String fromToken, final boolean isCatchingUp) {
if (!isAlive()) {
Log.e(LOG_TAG, "manageResponse : ignored because the session has been closed");
return;
}
boolean isInitialSync = (null == fromToken);
boolean isEmptyResponse = true;
// sanity check
if (null != syncResponse) {
Log.d(LOG_TAG, "onSyncComplete");
// to ensure to decrypt them properly
if ((null != syncResponse.toDevice) && (null != syncResponse.toDevice.events) && (syncResponse.toDevice.events.size() > 0)) {
Log.d(LOG_TAG, "manageResponse : receives " + syncResponse.toDevice.events.size() + " toDevice events");
for (Event toDeviceEvent : syncResponse.toDevice.events) {
handleToDeviceEvent(toDeviceEvent);
}
}
// to be able to update direct chats dictionary during invites handling.
if (null != syncResponse.accountData) {
Log.d(LOG_TAG, "Received " + syncResponse.accountData.size() + " accountData events");
manageAccountData(syncResponse.accountData, isInitialSync);
}
// sanity check
if (null != syncResponse.rooms) {
// joined rooms events
if ((null != syncResponse.rooms.join) && (syncResponse.rooms.join.size() > 0)) {
Log.d(LOG_TAG, "Received " + syncResponse.rooms.join.size() + " joined rooms");
Set<String> roomIds = syncResponse.rooms.join.keySet();
// Handle first joined rooms
for (String roomId : roomIds) {
try {
if (null != mLeftRoomsStore.getRoom(roomId)) {
Log.d(LOG_TAG, "the room " + roomId + " moves from left to the joined ones");
mLeftRoomsStore.deleteRoom(roomId);
}
getRoom(roomId).handleJoinedRoomSync(syncResponse.rooms.join.get(roomId), isInitialSync);
} catch (Exception e) {
Log.e(LOG_TAG, "## manageResponse() : handleJoinedRoomSync failed " + e.getMessage() + " for room " + roomId);
}
}
isEmptyResponse = false;
}
// invited room management
if ((null != syncResponse.rooms.invite) && (syncResponse.rooms.invite.size() > 0)) {
Log.d(LOG_TAG, "Received " + syncResponse.rooms.invite.size() + " invited rooms");
Set<String> roomIds = syncResponse.rooms.invite.keySet();
HashMap<String, List<String>> updatedDirectChatRoomsDict = null;
boolean hasChanged = false;
for (String roomId : roomIds) {
try {
Log.d(LOG_TAG, "## manageResponse() : the user has been invited to " + roomId);
if (null != mLeftRoomsStore.getRoom(roomId)) {
Log.d(LOG_TAG, "the room " + roomId + " moves from left to the invited ones");
mLeftRoomsStore.deleteRoom(roomId);
}
Room room = getRoom(roomId);
InvitedRoomSync invitedRoomSync = syncResponse.rooms.invite.get(roomId);
room.handleInvitedRoomSync(invitedRoomSync);
// Handle here the invites to a direct chat.
if (room.isDirectChatInvitation()) {
// Retrieve the inviter user id.
String participantUserId = null;
for (Event event : invitedRoomSync.inviteState.events) {
if (null != event.sender) {
participantUserId = event.sender;
break;
}
}
if (null != participantUserId) {
// Prepare the updated dictionary.
if (null == updatedDirectChatRoomsDict) {
if (null != this.getStore().getDirectChatRoomsDict()) {
// Consider the current dictionary.
updatedDirectChatRoomsDict = new HashMap<>(this.getStore().getDirectChatRoomsDict());
} else {
updatedDirectChatRoomsDict = new HashMap<>();
}
}
ArrayList<String> roomIdsList;
if (updatedDirectChatRoomsDict.containsKey(participantUserId)) {
roomIdsList = new ArrayList<>(updatedDirectChatRoomsDict.get(participantUserId));
} else {
roomIdsList = new ArrayList<>();
}
// Check whether the room was not yet seen as direct chat
if (roomIdsList.indexOf(roomId) < 0) {
Log.d(LOG_TAG, "## manageResponse() : add this new invite in direct chats");
// update room list with the new room
roomIdsList.add(roomId);
updatedDirectChatRoomsDict.put(participantUserId, roomIdsList);
hasChanged = true;
}
}
}
} catch (Exception e) {
Log.e(LOG_TAG, "## manageResponse() : handleInvitedRoomSync failed " + e.getMessage() + " for room " + roomId);
}
}
isEmptyResponse = false;
if (hasChanged) {
mAccountDataRestClient.setAccountData(mCredentials.userId, AccountDataRestClient.ACCOUNT_DATA_TYPE_DIRECT_MESSAGES, updatedDirectChatRoomsDict, new ApiCallback<Void>() {
@Override
public void onSuccess(Void info) {
Log.d(LOG_TAG, "## manageResponse() : succeeds");
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "## manageResponse() : update account data failed " + e.getMessage());
// TODO: we should try again.
}
@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "## manageResponse() : update account data failed " + e.getMessage());
}
@Override
public void onUnexpectedError(Exception e) {
Log.e(LOG_TAG, "## manageResponse() : update account data failed " + e.getMessage());
}
});
}
}
// when inviting after leaving a room, the room is defined in the both leave & invite rooms list.
if ((null != syncResponse.rooms.leave) && (syncResponse.rooms.leave.size() > 0)) {
Log.d(LOG_TAG, "Received " + syncResponse.rooms.leave.size() + " left rooms");
Set<String> roomIds = syncResponse.rooms.leave.keySet();
for (String roomId : roomIds) {
// RoomSync leftRoomSync = syncResponse.rooms.leave.get(roomId);
// Presently we remove the existing room from the rooms list.
// FIXME SYNC V2 Archive/Display the left rooms!
// For that create 'handleArchivedRoomSync' method
String membership = RoomMember.MEMBERSHIP_LEAVE;
Room room = getRoom(roomId);
// check if the room still exists.
if (null != room) {
// use 'handleJoinedRoomSync' to pass the last events to the room before leaving it.
// The room will then able to notify its listeners.
room.handleJoinedRoomSync(syncResponse.rooms.leave.get(roomId), isInitialSync);
RoomMember member = room.getMember(getUserId());
if (null != member) {
membership = member.membership;
}
Log.d(LOG_TAG, "## manageResponse() : leave the room " + roomId);
}
if (!TextUtils.equals(membership, RoomMember.MEMBERSHIP_KICK) && !TextUtils.equals(membership, RoomMember.MEMBERSHIP_BAN)) {
// ensure that the room data are properly deleted
this.getStore().deleteRoom(roomId);
onLeaveRoom(roomId);
} else {
onRoomKick(roomId);
}
// don't add to the left rooms if the user has been kicked / banned
if ((mAreLeftRoomsSynced) && TextUtils.equals(membership, RoomMember.MEMBERSHIP_LEAVE)) {
Room leftRoom = getRoom(mLeftRoomsStore, roomId, true);
leftRoom.handleJoinedRoomSync(syncResponse.rooms.leave.get(roomId), isInitialSync);
}
}
isEmptyResponse = false;
}
}
// groups
if (null != syncResponse.groups) {
// Handle invited groups
if ((null != syncResponse.groups.invite) && !syncResponse.groups.invite.isEmpty()) {
// Handle invited groups
for (String groupId : syncResponse.groups.invite.keySet()) {
InvitedGroupSync invitedGroupSync = syncResponse.groups.invite.get(groupId);
mGroupsManager.onNewGroupInvitation(groupId, invitedGroupSync.profile, invitedGroupSync.inviter, !isInitialSync);
}
}
// Handle joined groups
if ((null != syncResponse.groups.join) && !syncResponse.groups.join.isEmpty()) {
for (String groupId : syncResponse.groups.join.keySet()) {
mGroupsManager.onJoinGroup(groupId, !isInitialSync);
}
}
// Handle left groups
if ((null != syncResponse.groups.leave) && !syncResponse.groups.leave.isEmpty()) {
// Handle joined groups
for (String groupId : syncResponse.groups.leave.keySet()) {
mGroupsManager.onLeaveGroup(groupId, !isInitialSync);
}
}
}
// Handle presence of other users
if ((null != syncResponse.presence) && (null != syncResponse.presence.events)) {
Log.d(LOG_TAG, "Received " + syncResponse.presence.events.size() + " presence events");
for (Event presenceEvent : syncResponse.presence.events) {
handlePresenceEvent(presenceEvent);
}
}
if (null != mCrypto) {
mCrypto.onSyncCompleted(syncResponse, fromToken, isCatchingUp);
}
IMXStore store = getStore();
if (!isEmptyResponse && (null != store)) {
store.setEventStreamToken(syncResponse.nextBatch);
store.commit();
}
}
if (isInitialSync) {
if (!isCatchingUp) {
startCrypto(true);
} else {
// the events thread sends a dummy initial sync event
// when the application is restarted.
mIsStartingCryptoWithInitialSync = !isEmptyResponse;
}
onInitialSyncComplete((null != syncResponse) ? syncResponse.nextBatch : null);
} else {
if (!isCatchingUp) {
startCrypto(mIsStartingCryptoWithInitialSync);
}
try {
onLiveEventsChunkProcessed(fromToken, (null != syncResponse) ? syncResponse.nextBatch : fromToken);
} catch (Exception e) {
Log.e(LOG_TAG, "onLiveEventsChunkProcessed failed " + e.getMessage());
}
try {
// check if an incoming call has been received
mCallsManager.checkPendingIncomingCalls();
} catch (Exception e) {
Log.e(LOG_TAG, "checkPendingIncomingCalls failed " + e + " " + e.getMessage());
}
}
}
use of org.matrix.androidsdk.rest.model.MatrixError in project matrix-android-sdk by matrix-org.
the class MXSession method markRoomsAsRead.
/**
* Send the read receipts to the latest room messages.
*
* @param roomsIterator the rooms list iterator
* @param callback the asynchronous callback
*/
private void markRoomsAsRead(final Iterator roomsIterator, final ApiCallback<Void> callback) {
if (roomsIterator.hasNext()) {
Room room = (Room) roomsIterator.next();
boolean isRequestSent = false;
if (mNetworkConnectivityReceiver.isConnected()) {
isRequestSent = room.markAllAsRead(new ApiCallback<Void>() {
@Override
public void onSuccess(Void anything) {
markRoomsAsRead(roomsIterator, callback);
}
@Override
public void onNetworkError(Exception e) {
if (null != callback) {
callback.onNetworkError(e);
}
}
@Override
public void onMatrixError(MatrixError e) {
if (null != callback) {
callback.onMatrixError(e);
}
}
@Override
public void onUnexpectedError(Exception e) {
if (null != callback) {
callback.onUnexpectedError(e);
}
}
});
} else {
// update the local data
room.sendReadReceipt();
}
if (!isRequestSent) {
markRoomsAsRead(roomsIterator, callback);
}
} else {
if (null != callback) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
callback.onSuccess(null);
}
});
}
}
}
use of org.matrix.androidsdk.rest.model.MatrixError in project matrix-android-sdk by matrix-org.
the class MXDeviceList method doKeyDownloadForUsers.
/**
* Download the devices keys for a set of users.
* It must be called in getEncryptingThreadHandler() thread.
* The callback is called in the UI thread.
*
* @param downloadUsers the user ids list
* @param callback the asynchronous callback
*/
private void doKeyDownloadForUsers(final List<String> downloadUsers, final ApiCallback<MXUsersDevicesMap<MXDeviceInfo>> callback) {
Log.d(LOG_TAG, "## doKeyDownloadForUsers() : doKeyDownloadForUsers " + downloadUsers);
// get the user ids which did not already trigger a keys download
final List<String> filteredUsers = addDownloadKeysPromise(downloadUsers, callback);
// if there is no new keys request
if (0 == filteredUsers.size()) {
// trigger nothing
return;
}
// sanity check
if ((null == mxSession.getDataHandler()) || (null == mxSession.getDataHandler().getStore())) {
return;
}
mIsDownloadingKeys = true;
// track the race condition while sending requests
// we defines a tag for each request
// and test if the response is the latest request one
final String downloadToken = filteredUsers.hashCode() + " " + System.currentTimeMillis();
for (String userId : filteredUsers) {
mPendingDownloadKeysRequestToken.put(userId, downloadToken);
}
mxSession.getCryptoRestClient().downloadKeysForUsers(filteredUsers, mxSession.getDataHandler().getStore().getEventStreamToken(), new ApiCallback<KeysQueryResponse>() {
@Override
public void onSuccess(final KeysQueryResponse keysQueryResponse) {
mxCrypto.getEncryptingThreadHandler().post(new Runnable() {
@Override
public void run() {
Log.d(LOG_TAG, "## doKeyDownloadForUsers() : Got keys for " + filteredUsers.size() + " users");
MXDeviceInfo myDevice = mxCrypto.getMyDevice();
IMXCryptoStore cryptoStore = mxCrypto.getCryptoStore();
List<String> userIdsList = new ArrayList<>(filteredUsers);
for (String userId : userIdsList) {
// test if the response is the latest request one
if (!TextUtils.equals(mPendingDownloadKeysRequestToken.get(userId), downloadToken)) {
Log.e(LOG_TAG, "## doKeyDownloadForUsers() : Another update in the queue for " + userId + " not marking up-to-date");
filteredUsers.remove(userId);
} else {
Map<String, MXDeviceInfo> devices = keysQueryResponse.deviceKeys.get(userId);
Log.d(LOG_TAG, "## doKeyDownloadForUsers() : Got keys for " + userId + " : " + devices);
if (null != devices) {
HashMap<String, MXDeviceInfo> mutableDevices = new HashMap<>(devices);
ArrayList<String> deviceIds = new ArrayList<>(mutableDevices.keySet());
for (String deviceId : deviceIds) {
// the user has been logged out
if (null == cryptoStore) {
break;
}
// Get the potential previously store device keys for this device
MXDeviceInfo previouslyStoredDeviceKeys = cryptoStore.getUserDevice(deviceId, userId);
MXDeviceInfo deviceInfo = mutableDevices.get(deviceId);
// the self device must be seen as verified
if (TextUtils.equals(deviceInfo.deviceId, myDevice.deviceId) && TextUtils.equals(userId, myDevice.userId)) {
deviceInfo.mVerified = MXDeviceInfo.DEVICE_VERIFICATION_VERIFIED;
}
// Validate received keys
if (!validateDeviceKeys(deviceInfo, userId, deviceId, previouslyStoredDeviceKeys)) {
// New device keys are not valid. Do not store them
mutableDevices.remove(deviceId);
if (null != previouslyStoredDeviceKeys) {
// But keep old validated ones if any
mutableDevices.put(deviceId, previouslyStoredDeviceKeys);
}
} else if (null != previouslyStoredDeviceKeys) {
// The verified status is not sync'ed with hs.
// This is a client side information, valid only for this client.
// So, transfer its previous value
mutableDevices.get(deviceId).mVerified = previouslyStoredDeviceKeys.mVerified;
}
}
// Update the store
// Note that devices which aren't in the response will be removed from the stores
cryptoStore.storeUserDevices(userId, mutableDevices);
}
// the response is the latest request one
mPendingDownloadKeysRequestToken.remove(userId);
}
}
onKeysDownloadSucceed(filteredUsers, keysQueryResponse.failures);
}
});
}
private void onFailed() {
mxCrypto.getEncryptingThreadHandler().post(new Runnable() {
@Override
public void run() {
List<String> userIdsList = new ArrayList<>(filteredUsers);
// test if the response is the latest request one
for (String userId : userIdsList) {
if (!TextUtils.equals(mPendingDownloadKeysRequestToken.get(userId), downloadToken)) {
Log.e(LOG_TAG, "## doKeyDownloadForUsers() : Another update in the queue for " + userId + " not marking up-to-date");
filteredUsers.remove(userId);
} else {
// the response is the latest request one
mPendingDownloadKeysRequestToken.remove(userId);
}
}
onKeysDownloadFailed(filteredUsers);
}
});
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onNetworkError " + e.getMessage());
onFailed();
if (null != callback) {
callback.onNetworkError(e);
}
}
@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onMatrixError " + e.getMessage());
onFailed();
if (null != callback) {
callback.onMatrixError(e);
}
}
@Override
public void onUnexpectedError(Exception e) {
Log.e(LOG_TAG, "##doKeyDownloadForUsers() : onUnexpectedError " + e.getMessage());
onFailed();
if (null != callback) {
callback.onUnexpectedError(e);
}
}
});
}
use of org.matrix.androidsdk.rest.model.MatrixError in project matrix-android-sdk by matrix-org.
the class MXCallsManager method refreshTurnServer.
/**
* Refresh the turn servers.
*/
private void refreshTurnServer() {
if (mSuspendTurnServerRefresh) {
return;
}
Log.d(LOG_TAG, "## refreshTurnServer () starts");
mUIThreadHandler.post(new Runnable() {
@Override
public void run() {
mCallResClient.getTurnServer(new ApiCallback<JsonObject>() {
private void restartAfter(int msDelay) {
// "ttl" seems invalid
if (msDelay <= 0) {
Log.e(LOG_TAG, "## refreshTurnServer() : invalid delay " + msDelay);
} else {
if (null != mTurnServerTimer) {
mTurnServerTimer.cancel();
}
try {
mTurnServerTimer = new Timer();
mTurnServerTimer.schedule(new TimerTask() {
@Override
public void run() {
if (mTurnServerTimer != null) {
mTurnServerTimer.cancel();
mTurnServerTimer = null;
}
refreshTurnServer();
}
}, msDelay);
} catch (Throwable e) {
Log.e(LOG_TAG, "## refreshTurnServer() failed to start the timer");
if (null != mTurnServerTimer) {
mTurnServerTimer.cancel();
mTurnServerTimer = null;
}
refreshTurnServer();
}
}
}
@Override
public void onSuccess(JsonObject info) {
// privacy
Log.d(LOG_TAG, "## refreshTurnServer () : onSuccess");
if (null != info) {
if (info.has("uris")) {
synchronized (LOG_TAG) {
mTurnServer = info;
}
}
if (info.has("ttl")) {
int ttl = 60000;
try {
ttl = info.get("ttl").getAsInt();
// restart a 90 % before ttl expires
ttl = ttl * 9 / 10;
} catch (Exception e) {
Log.e(LOG_TAG, "Fail to retrieve ttl " + e.getMessage());
}
Log.d(LOG_TAG, "## refreshTurnServer () : onSuccess : retry after " + ttl + " seconds");
restartAfter(ttl * 1000);
}
}
}
@Override
public void onNetworkError(Exception e) {
Log.e(LOG_TAG, "## refreshTurnServer () : onNetworkError " + e);
restartAfter(60000);
}
@Override
public void onMatrixError(MatrixError e) {
Log.e(LOG_TAG, "## refreshTurnServer () : onMatrixError() : " + e.errcode);
if (TextUtils.equals(e.errcode, MatrixError.LIMIT_EXCEEDED) && (null != e.retry_after_ms)) {
Log.e(LOG_TAG, "## refreshTurnServer () : onMatrixError() : retry after " + e.retry_after_ms + " ms");
restartAfter(e.retry_after_ms);
}
}
@Override
public void onUnexpectedError(Exception e) {
// should never happen
}
});
}
});
}
Aggregations