use of org.matrix.androidsdk.rest.model.sync.SyncResponse in project matrix-android-sdk by matrix-org.
the class MXDataHandler method retrieveLeftRooms.
/**
* Retrieve the historical rooms
*
* @param callback the asynchronous callback.
*/
public void retrieveLeftRooms(ApiCallback<Void> callback) {
// already loaded
if (mAreLeftRoomsSynced) {
if (null != callback) {
callback.onSuccess(null);
}
} else {
int count;
synchronized (mLeftRoomsRefreshCallbacks) {
if (null != callback) {
mLeftRoomsRefreshCallbacks.add(callback);
}
count = mLeftRoomsRefreshCallbacks.size();
}
// start the request only for the first listener
if (1 == count) {
mIsRetrievingLeftRooms = true;
Log.d(LOG_TAG, "## refreshHistoricalRoomsList() : requesting");
mEventsRestClient.syncFromToken(null, 0, 30000, null, LEFT_ROOMS_FILTER, new ApiCallback<SyncResponse>() {
@Override
public void onSuccess(final SyncResponse syncResponse) {
Runnable r = new Runnable() {
@Override
public void run() {
if (null != syncResponse.rooms.leave) {
Set<String> roomIds = syncResponse.rooms.leave.keySet();
// Handle first joined rooms
for (String roomId : roomIds) {
Room room = getRoom(mLeftRoomsStore, roomId, true);
// sanity check
if (null != room) {
room.setIsLeft(true);
room.handleJoinedRoomSync(syncResponse.rooms.leave.get(roomId), true);
RoomMember selfMember = room.getState().getMember(getUserId());
// keep only the left rooms (i.e not the banned / kicked ones)
if ((null == selfMember) || !TextUtils.equals(selfMember.membership, RoomMember.MEMBERSHIP_LEAVE)) {
mLeftRoomsStore.deleteRoom(roomId);
}
}
}
Log.d(LOG_TAG, "## refreshHistoricalRoomsList() : " + mLeftRoomsStore.getRooms().size() + " left rooms");
}
mIsRetrievingLeftRooms = false;
mAreLeftRoomsSynced = true;
synchronized (mLeftRoomsRefreshCallbacks) {
for (ApiCallback<Void> c : mLeftRoomsRefreshCallbacks) {
c.onSuccess(null);
}
mLeftRoomsRefreshCallbacks.clear();
}
}
};
Thread t = new Thread(r);
t.setPriority(Thread.MIN_PRIORITY);
t.start();
}
@Override
public void onNetworkError(Exception e) {
synchronized (mLeftRoomsRefreshCallbacks) {
Log.d(LOG_TAG, "## refreshHistoricalRoomsList() : failed " + e.getMessage());
for (ApiCallback<Void> c : mLeftRoomsRefreshCallbacks) {
c.onNetworkError(e);
}
mLeftRoomsRefreshCallbacks.clear();
}
}
@Override
public void onMatrixError(MatrixError e) {
synchronized (mLeftRoomsRefreshCallbacks) {
Log.d(LOG_TAG, "## refreshHistoricalRoomsList() : failed " + e.getMessage());
for (ApiCallback<Void> c : mLeftRoomsRefreshCallbacks) {
c.onMatrixError(e);
}
mLeftRoomsRefreshCallbacks.clear();
}
}
@Override
public void onUnexpectedError(Exception e) {
synchronized (mLeftRoomsRefreshCallbacks) {
Log.d(LOG_TAG, "## refreshHistoricalRoomsList() : failed " + e.getMessage());
for (ApiCallback<Void> c : mLeftRoomsRefreshCallbacks) {
c.onUnexpectedError(e);
}
mLeftRoomsRefreshCallbacks.clear();
}
}
});
}
}
}
use of org.matrix.androidsdk.rest.model.sync.SyncResponse in project matrix-android-sdk by matrix-org.
the class EventsThread method startSync.
/**
* Start the events sync
*/
@SuppressLint("NewApi")
private void startSync() {
if (null != mCurrentToken) {
Log.d(LOG_TAG, "Resuming initial sync from " + mCurrentToken);
} else {
Log.d(LOG_TAG, "Requesting initial sync...");
}
int serverTimeout;
mPaused = false;
//
mInitialSyncDone = null != mCurrentToken;
if (mInitialSyncDone) {
// get the latest events asap
serverTimeout = 0;
// dummy initial sync
// to hide the splash screen
SyncResponse dummySyncResponse = new SyncResponse();
dummySyncResponse.nextBatch = mCurrentToken;
mListener.onSyncResponse(dummySyncResponse, null, true);
} else {
// Start with initial sync
while (!mInitialSyncDone) {
final CountDownLatch latch = new CountDownLatch(1);
mEventsRestClient.syncFromToken(null, 0, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", DATA_SAVE_MODE_FILTER, new SimpleApiCallback<SyncResponse>(mFailureCallback) {
@Override
public void onSuccess(SyncResponse syncResponse) {
Log.d(LOG_TAG, "Received initial sync response.");
mNextServerTimeoutms = hasDevicesChanged(syncResponse) ? 0 : mDefaultServerTimeoutms;
mListener.onSyncResponse(syncResponse, null, (0 == mNextServerTimeoutms));
mCurrentToken = syncResponse.nextBatch;
mInitialSyncDone = true;
// unblock the events thread
latch.countDown();
}
private void sleepAndUnblock() {
Log.i(LOG_TAG, "Waiting a bit before retrying");
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
public void run() {
latch.countDown();
}
}, RETRY_WAIT_TIME_MS);
}
@Override
public void onNetworkError(Exception e) {
if (null != mCurrentToken) {
onSuccess(null);
} else {
Log.e(LOG_TAG, "Sync V2 onNetworkError " + e.getMessage());
super.onNetworkError(e);
sleepAndUnblock();
}
}
@Override
public void onMatrixError(MatrixError e) {
super.onMatrixError(e);
if (MatrixError.isConfigurationErrorCode(e.errcode)) {
mListener.onConfigurationError(e.errcode);
} else {
sleepAndUnblock();
}
}
@Override
public void onUnexpectedError(Exception e) {
super.onUnexpectedError(e);
Log.e(LOG_TAG, "Sync V2 onUnexpectedError " + e.getMessage());
sleepAndUnblock();
}
});
// block until the initial sync callback is invoked.
try {
latch.await();
} catch (InterruptedException e) {
Log.e(LOG_TAG, "Interrupted whilst performing initial sync.");
} catch (Exception e) {
Log.e(LOG_TAG, "## startSync() failed " + e.getMessage());
}
}
serverTimeout = mNextServerTimeoutms;
}
Log.d(LOG_TAG, "Starting event stream from token " + mCurrentToken);
// sanity check
if (null != mNetworkConnectivityReceiver) {
mNetworkConnectivityReceiver.addEventListener(mNetworkListener);
//
mbIsConnected = mNetworkConnectivityReceiver.isConnected();
mIsNetworkSuspended = !mbIsConnected;
}
// Then repeatedly long-poll for events
while (!mKilling) {
// test if a delay between two syncs
if ((!mPaused && !mIsNetworkSuspended) && (0 != mRequestDelayMs)) {
Log.d(LOG_TAG, "startSync : start a delay timer ");
Intent intent = new Intent(mContext, SyncDelayReceiver.class);
intent.putExtra(SyncDelayReceiver.EXTRA_INSTANCE_ID, this.toString());
mPendingDelayedIntent = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
long futureInMillis = SystemClock.elapsedRealtime() + mRequestDelayMs;
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) && mPowerManager.isIgnoringBatteryOptimizations(mContext.getPackageName())) {
mAlarmManager.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, mPendingDelayedIntent);
} else {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, futureInMillis, mPendingDelayedIntent);
}
}
if (mPaused || mIsNetworkSuspended || (null != mPendingDelayedIntent)) {
if (null != mPendingDelayedIntent) {
Log.d(LOG_TAG, "Event stream is paused because there is a timer delay.");
} else if (mIsNetworkSuspended) {
Log.d(LOG_TAG, "Event stream is paused because there is no available network.");
} else {
Log.d(LOG_TAG, "Event stream is paused. Waiting.");
}
try {
Log.d(LOG_TAG, "startSync : wait ...");
synchronized (mSyncObject) {
mSyncObject.wait();
}
if (null != mPendingDelayedIntent) {
Log.d(LOG_TAG, "startSync : cancel mSyncDelayTimer");
mAlarmManager.cancel(mPendingDelayedIntent);
mPendingDelayedIntent.cancel();
mPendingDelayedIntent = null;
}
Log.d(LOG_TAG, "Event stream woken from pause.");
// perform a catchup asap
serverTimeout = 0;
} catch (InterruptedException e) {
Log.e(LOG_TAG, "Unexpected interruption while paused: " + e.getMessage());
}
}
// the service could have been killed while being paused.
if (!mKilling) {
// "{\"room\":{\"timeline\":{\"limit\":250}}}";
String inlineFilter = mIsInDataSaveMode ? DATA_SAVE_MODE_FILTER : null;
final CountDownLatch latch = new CountDownLatch(1);
if (mIsInDataSaveMode) {
Log.d(LOG_TAG, "[Data save mode] Get events from token " + mCurrentToken);
} else {
Log.d(LOG_TAG, "Get events from token " + mCurrentToken);
}
final int fServerTimeout = serverTimeout;
mNextServerTimeoutms = mDefaultServerTimeoutms;
mEventsRestClient.syncFromToken(mCurrentToken, serverTimeout, DEFAULT_CLIENT_TIMEOUT_MS, mIsOnline ? null : "offline", inlineFilter, new SimpleApiCallback<SyncResponse>(mFailureCallback) {
@Override
public void onSuccess(SyncResponse syncResponse) {
if (!mKilling) {
// we get no to_device messages back.
if (0 == fServerTimeout) {
if (hasDevicesChanged(syncResponse)) {
if (mIsCatchingUp) {
Log.d(LOG_TAG, "Some devices have changed but do not set mNextServerTimeoutms to 0 to avoid infinite loops");
} else {
Log.d(LOG_TAG, "mNextServerTimeoutms is set to 0 because of hasDevicesChanged " + syncResponse.deviceLists.changed);
mNextServerTimeoutms = 0;
}
}
}
// to loop again
if (mIsCatchingUp && (0 != mNextServerTimeoutms)) {
// the catchup triggers sync requests until there are some useful events
int eventCounts = 0;
if (null != syncResponse.rooms) {
RoomsSyncResponse roomsSyncResponse = syncResponse.rooms;
if (null != roomsSyncResponse.join) {
eventCounts += roomsSyncResponse.join.size();
}
if (null != roomsSyncResponse.invite) {
eventCounts += roomsSyncResponse.invite.size();
}
}
// stop any catch up
mIsCatchingUp = false;
mPaused = (0 == mRequestDelayMs);
Log.d(LOG_TAG, "Got " + eventCounts + " useful events while catching up : mPaused is set to " + mPaused);
}
Log.d(LOG_TAG, "Got event response");
mListener.onSyncResponse(syncResponse, mCurrentToken, (0 == mNextServerTimeoutms));
mCurrentToken = syncResponse.nextBatch;
Log.d(LOG_TAG, "mCurrentToken is now set to " + mCurrentToken);
}
// unblock the events thread
latch.countDown();
}
private void onError(String description) {
boolean isConnected;
Log.d(LOG_TAG, "Got an error while polling events " + description);
synchronized (mSyncObject) {
isConnected = mbIsConnected;
}
// detected if the device is connected before trying again
if (isConnected) {
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
public void run() {
latch.countDown();
}
}, RETRY_WAIT_TIME_MS);
} else {
// no network -> wait that a network connection comes back.
mIsNetworkSuspended = true;
latch.countDown();
}
}
@Override
public void onNetworkError(Exception e) {
onError(e.getLocalizedMessage());
}
@Override
public void onMatrixError(MatrixError e) {
if (MatrixError.isConfigurationErrorCode(e.errcode)) {
mListener.onConfigurationError(e.errcode);
} else {
onError(e.getLocalizedMessage());
}
}
@Override
public void onUnexpectedError(Exception e) {
onError(e.getLocalizedMessage());
}
});
// block until the sync callback is invoked.
try {
latch.await();
} catch (InterruptedException e) {
Log.e(LOG_TAG, "Interrupted whilst polling message");
} catch (Exception e) {
// reported by GA
// The thread might have been killed.
Log.e(LOG_TAG, "latch.await() failed " + e.getMessage());
}
}
serverTimeout = mNextServerTimeoutms;
}
if (null != mNetworkConnectivityReceiver) {
mNetworkConnectivityReceiver.removeEventListener(mNetworkListener);
}
Log.d(LOG_TAG, "Event stream terminating.");
}
Aggregations