Search in sources :

Example 1 with SyncResponse

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();
                    }
                }
            });
        }
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) BingRuleSet(org.matrix.androidsdk.rest.model.bingrules.BingRuleSet) ApiCallback(org.matrix.androidsdk.rest.callback.ApiCallback) SimpleApiCallback(org.matrix.androidsdk.rest.callback.SimpleApiCallback) MXDecryptionException(org.matrix.androidsdk.crypto.MXDecryptionException) UnrecognizedCertificateException(org.matrix.androidsdk.ssl.UnrecognizedCertificateException) HandlerThread(android.os.HandlerThread) SyncResponse(org.matrix.androidsdk.rest.model.sync.SyncResponse) RoomMember(org.matrix.androidsdk.rest.model.RoomMember) MatrixError(org.matrix.androidsdk.rest.model.MatrixError) Room(org.matrix.androidsdk.data.Room)

Example 2 with SyncResponse

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.");
}
Also used : Handler(android.os.Handler) Intent(android.content.Intent) PendingIntent(android.app.PendingIntent) RoomsSyncResponse(org.matrix.androidsdk.rest.model.sync.RoomsSyncResponse) CountDownLatch(java.util.concurrent.CountDownLatch) SuppressLint(android.annotation.SuppressLint) RoomsSyncResponse(org.matrix.androidsdk.rest.model.sync.RoomsSyncResponse) SyncResponse(org.matrix.androidsdk.rest.model.sync.SyncResponse) MatrixError(org.matrix.androidsdk.rest.model.MatrixError) SuppressLint(android.annotation.SuppressLint)

Aggregations

MatrixError (org.matrix.androidsdk.rest.model.MatrixError)2 SyncResponse (org.matrix.androidsdk.rest.model.sync.SyncResponse)2 SuppressLint (android.annotation.SuppressLint)1 PendingIntent (android.app.PendingIntent)1 Intent (android.content.Intent)1 Handler (android.os.Handler)1 HandlerThread (android.os.HandlerThread)1 HashSet (java.util.HashSet)1 Set (java.util.Set)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 MXDecryptionException (org.matrix.androidsdk.crypto.MXDecryptionException)1 Room (org.matrix.androidsdk.data.Room)1 ApiCallback (org.matrix.androidsdk.rest.callback.ApiCallback)1 SimpleApiCallback (org.matrix.androidsdk.rest.callback.SimpleApiCallback)1 RoomMember (org.matrix.androidsdk.rest.model.RoomMember)1 BingRuleSet (org.matrix.androidsdk.rest.model.bingrules.BingRuleSet)1 RoomsSyncResponse (org.matrix.androidsdk.rest.model.sync.RoomsSyncResponse)1 UnrecognizedCertificateException (org.matrix.androidsdk.ssl.UnrecognizedCertificateException)1